Experiment gameplan

Text

Text: Experiment gameplan
  1. Use GffRead to filter Trinity-derived GMAP-aligned gff3 files.
  2. Use featureCounts htseq-count to perform feature counting with respect to types “locus”, “mRNA”, “exon”, and “CDS” features from “base” calls to GffRead, and with respect to type “gene” from “intron-filtering-only” calls to GffRead.
  3. Read in resulting counts matrices and gtf files using custom R code; perform processing as necessary using a mix of bioconductor and tidyverse programs.
  4. In terms of raw, non-normalized alignment-to-putative transcript/transcript fragment (transfrag) tallies, retain putative transcripts/transfrags with tallies greater than or equal to a given percentile; in this case, generate results for the 5th to 95th percentiles in iterations of five.
  5. Use rtracklayer custom code to write the converted, collapsed, counts-filtered data objects as gtf files.
  6. Send the processed gtf files to Alison Greenlaw for inspection.
For both Q and G1, Alison asked me to filter the assemblies generated with Trinity parameter mkc = 1, 4, 8. However, for the sake of completeness, and to understand clearly what “incorrectness” looks like, I will filter mkc = 2, 16, 32 as well. Remember that the Trinity parameters mir, mg, and gf were held at default levels for the specific assemblies to surveyed by Alison.



Additional details

Text, code

Text, code: Additional details

I. On calling gffread

#!/bin/bash

#  "Base" call to GffRead
gffread \
    -v \
    -g "${fasta_g}" \
    -i 1000 \
    -Z \
    -M -K -Q \
    -F -N -P \
    --force-exons --gene2exon \
    -o "${out}" \
    <(awk -F '\t' 'BEGIN {OFS = FS} { gsub(/chr/, "", $1); gsub(/M/, "Mito", $1); print }' "${in}") \
         > >(tee -a "${err_out%.}.stdout.txt") \
        2> >(tee -a "${err_out%.}.stderr.txt")

#  "Intron-filtering-only" call to GffRead
#+ 
#+ No collapsing, merging with these files; only filtering to exclude exonic
#+ features with introns greater than 1000 bp in length
gffread \
    -v -O \
    -i 1000 \
    -o "${out/.gff3/-intron-filtering-only.gff3}" \
    <(awk -F '\t' 'BEGIN {OFS = FS} { gsub(/chr/, "", $1); gsub(/M/, "Mito", $1); print }' "${in}") \
         > >(tee -a "${err_out%.}-intron-filtering-only.stdout.txt") \
        2> >(tee -a "${err_out%.}-intron-filtering-only.stderr.txt")
Meaning of parameters
“Base” call to GffRead
  • -v expose (warn about) duplicate transcript IDs and other potential problems with the given GFF/GTF records
  • -g full path to a fasta file with the genomic sequences for all input mappings (one per genomic sequence, with file names matching sequence names) (#NOTE i.e., the fasta - file output from running Trinity in genome-guided mode)
  • -i discard transcripts having an intron larger than 1000 bp
  • -Z merge very close exons into a single exon (when intron size<4)
  • -M cluster the input transcripts into loci, discarding “redundant” transcripts (those with the same exact introns and fully contained or equal boundaries)
  • -K for the -M option, also discard as redundant the shorter, fully contained transcripts (intron chains matching a part of the container)
  • -Q for the -M option, no longer require boundary containment when assessing redundancy (can be combined with -K); only introns have to match for multi-exon transcripts, and >=80% overlap for single-exon transcripts
  • -F keep all GFF attributes (for non-exon features)
  • -N discard multi-exon mRNAs that have any intron with a non-canonical splice site consensus (i.e., not GT-AG, GC-AG or AT-AC)
  • -P add transcript level GFF attributes about the coding status of each transcript, including partialness or in-frame stop codons (requires -g)
  • --force-exons make sure that the lowest level GFF features are considered “exon” features (#NOTE This is standard in gff3 and gtf files)
  • -o write the output records into instead of stdout
“Intron-filtering-only” call to GffRead
  • -v expose (warn about) duplicate transcript IDs and other potential problems with the given GFF/GTF records
  • -O process other non-transcript GFF records (by default non-transcript records are ignored) (#NOTE This keeps ‘gene’ features (output by gmap) in the gff3/gtf, although “gene” is exactly the same as “mRNA” as output by gmap)
  • -i discard transcripts having an intron larger than 1000 bp
  • -o write the output records into instead of stdout

II. On calling htseq-count

…with respect to type “locus”

As a result of calling gffread with the -Z -M -K and -Q arguments, a new feature is added to the gff3/gtf files: “locus”. “locus” is a putative parent feature made from collapsing and joining “children” features (hierarchically, “mRNA” and “exon”) as described for -Z -M -K and -Q. This is an extension of the kind of collapsing performed by gffcompare -C. Thus, counts matrices were created with respect to these “locus” features.

#!/bin/bash

sbatch \
    --job-name="htseq-count-locus" \
    --nodes=1 \
    --cpus-per-task=8 \
    --error="${err_out}-locus.%A.stderr.txt" \
    --output="${err_out}-locus.%A.stdout.txt" \
    htseq-count \
        --order "pos" \
        --stranded "${hc_strd}" \
        --nonunique "all" \
        --type "locus" \
        --idattr "ID" \
        --nprocesses 8 \
        --counts_output "${out/.tsv/-locus.tsv}" \
        --with-header \
        ${bams[*]} \
        "${in}"
…with respect to type “mRNA”

Create the counts matrix by looking at children “mRNA” features rather than parent “locus” features. This is the kind of collapsing performed by gffcompare -C.

#!/bin/bash

sbatch \
    --job-name="htseq-count-mRNA" \
    --nodes=1 \
    --cpus-per-task=8 \
    --error="${err_out}-mRNA.%A.stderr.txt" \
    --output="${err_out}-mRNA.%A.stdout.txt" \
    htseq-count \
        --order "pos" \
        --stranded "${hc_strd}" \
        --nonunique "all" \
        --type "mRNA" \
        --idattr "ID" \
        --nprocesses 8 \
        --counts_output "${out/.tsv/-mRNA.tsv}" \
        --with-header \
        ${bams[*]} \
        "${in}"
…with respect to type “exon”

Create the counts matrix by looking at children “exon” features.

#!/bin/bash

sbatch \
    --job-name="htseq-count-exon" \
    --nodes=1 \
    --cpus-per-task=8 \
    --error="${err_out}-exon.%A.stderr.txt" \
    --output="${err_out}-exon.%A.stdout.txt" \
    htseq-count \
        --order "pos" \
        --stranded "${hc_strd}" \
        --nonunique "all" \
        --type "exon" \
        --idattr "Parent" \
        --nprocesses 8 \
        --counts_output "${out/.tsv/-exon.tsv}" \
        --with-header \
        ${bams[*]} \
        "${in}"
…with respect to type “CDS”

gffread scans the fastas supplied -g and roughly estimates start and stop codons from the nt sequences; it then adds these CDS estimates to the gff3/gtf files. Create the counts matrix by looking at these estimated “CDS” features.

#!/bin/bash

sbatch \
    --job-name="htseq-count-CDS" \
    --nodes=1 \
    --cpus-per-task=8 \
    --error="${err_out}-CDS.%A.stderr.txt" \
    --output="${err_out}-CDS.%A.stdout.txt" \
    htseq-count \
        --order "pos" \
        --stranded "${hc_strd}" \
        --nonunique "all" \
        --type "CDS" \
        --idattr "Parent" \
        --nprocesses 8 \
        --counts_output "${out/.tsv/-CDS.tsv}" \
        --with-header \
        ${bams[*]} \
        "${in}"
…with respect to type “gene” (“intron-only-filtering” call to GffRead)

Create the counts matrix by looking at parent “gene” features from the files output in section “On calling gffread above.

#!/bin/bash
sbatch \
    --job-name="htseq-count-gene" \
    --nodes=1 \
    --cpus-per-task=8 \
    --error="${err_out}-gene.%A.stderr.txt" \
    --output="${err_out}-gene.%A.stdout.txt" \
    htseq-count \
        --order "pos" \
        --stranded "${hc_strd}" \
        --nonunique "all" \
        --type "gene" \
        --idattr "ID" \
        --nprocesses 8 \
        --counts_output "${out/.tsv/-gene.tsv}" \
        --with-header \
        ${bams[*]} \
        "${in}"


III. The general workflow for making the filtered gtfs

  1. Read in and process gtf/gff3 files (as dataframes)
  2. Read in and process counts matrices: “locus”, “mRNA”, “exon”, “CDS”, and “gene” (intron-only-filtering)
  3. Categorize putative transcripts/transfrags by percentile: from percentile 5 to percentile 95 in steps of 5
  4. Subset dataframes to retain percentile-filtered IDs: “locus”, “mRNA”, “exon”, “CDS”, and “gene” (intron-only-filtering)
  5. Write out processed gtfs

IV. Copying over files to Alison

#!/bin/bash

mkdir -p /home/kalavatt/tsukiyamalab/alisong/KA.gtfs_quantile-filtered_Trinity-GG_G1-Q_2023-0410/{gtf-gff3,tsv}
# mkdir: created directory '/home/kalavatt/tsukiyamalab/alisong/KA.gtfs_quantile-filtered_Trinity-GG_G1-Q_2023-0410'
# mkdir: created directory '/home/kalavatt/tsukiyamalab/alisong/KA.gtfs_quantile-filtered_Trinity-GG_G1-Q_2023-0410/gtf-gff3'
# mkdir: created directory '/home/kalavatt/tsukiyamalab/alisong/KA.gtfs_quantile-filtered_Trinity-GG_G1-Q_2023-0410/tsv'

cd /home/kalavatt/tsukiyamalab/kalavatt/2022_transcriptome-construction/results/2023-0215

cp -r \
    outfiles_gtf-gff3/Trinity-GG \
    /home/kalavatt/tsukiyamalab/alisong/KA.gtfs_quantile-filtered_Trinity-GG_G1-Q_2023-0410/gtf-gff3

cp -r \
    outfiles_htseq-count/Trinity-GG \
    /home/kalavatt/tsukiyamalab/alisong/KA.gtfs_quantile-filtered_Trinity-GG_G1-Q_2023-0410/tsv

#  Manually copying in the 'filtered/' subdirectories from local to remote



0–2. Command-line work

See work_assessment-processing_gtfs_part-0.md, where steps 0 through 3 are detailed. Below, we pick up with step 4.

3. Perform quantile filtering of putative transcripts/transfrags

Get situated

Code

Code: Get situated

#START

#!/usr/bin/env Rscript

library(GenomicRanges)
Loading required package: stats4
Loading required package: BiocGenerics

Attaching package: ‘BiocGenerics’

The following objects are masked from ‘package:stats’:

    IQR, mad, sd, var, xtabs

The following objects are masked from ‘package:base’:

    anyDuplicated, aperm, append, as.data.frame, basename, cbind, colnames, dirname, do.call, duplicated, eval, evalq, Filter, Find, get, grep,
    grepl, intersect, is.unsorted, lapply, Map, mapply, match, mget, order, paste, pmax, pmax.int, pmin, pmin.int, Position, rank, rbind, Reduce,
    rownames, sapply, setdiff, sort, table, tapply, union, unique, unsplit, which.max, which.min

Loading required package: S4Vectors

Attaching package: ‘S4Vectors’

The following objects are masked from ‘package:base’:

    expand.grid, I, unname

Loading required package: IRanges
Loading required package: GenomeInfoDb
library(IRanges)
library(readxl)
library(rtracklayer)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.2 ──✔ ggplot2 3.4.2     ✔ purrr   1.0.1
✔ tibble  3.2.1     ✔ dplyr   1.1.1
✔ tidyr   1.3.0     ✔ stringr 1.5.0
✔ readr   2.1.4     ✔ forcats 1.0.0Warning: package ‘ggplot2’ was built under R version 4.2.3Warning: package ‘tibble’ was built under R version 4.2.3Warning: package ‘dplyr’ was built under R version 4.2.3── Conflicts ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::collapse()   masks IRanges::collapse()
✖ dplyr::combine()    masks BiocGenerics::combine()
✖ dplyr::desc()       masks IRanges::desc()
✖ tidyr::expand()     masks S4Vectors::expand()
✖ dplyr::filter()     masks stats::filter()
✖ dplyr::first()      masks S4Vectors::first()
✖ dplyr::lag()        masks stats::lag()
✖ ggplot2::Position() masks BiocGenerics::Position(), base::Position()
✖ purrr::reduce()     masks GenomicRanges::reduce(), IRanges::reduce()
✖ dplyr::rename()     masks S4Vectors::rename()
✖ dplyr::slice()      masks IRanges::slice()
options(scipen = 999)
options(ggrepel.max.overlaps = Inf)

if(stringr::str_detect(getwd(), "kalavattam")) {
    p_local <- "/Users/kalavattam/Dropbox/FHCC"
} else {
    p_local <- "/Users/kalavatt/projects-etc"
}
p_wd <- "2022_transcriptome-construction/results/2023-0215"

setwd(paste(p_local, p_wd, sep = "/"))
getwd()
[1] "/Users/kalavatt/projects-etc/2022_transcriptome-construction/results/2023-0215"
rm(p_local, p_wd)


Read in and process gtf files (as data.frames)

Code

Code: Read in and process gtf files (as data.frames)
#!/usr/bin/env Rscript

#  Initialize functions ---------------
import_g <- function(file) {
    rtracklayer::import(file)
}


read_in_gtfs <- function(vector_files) {
    list <- sapply(
        vector_files,
        import_g,
        simplify = FALSE,
        USE.NAMES = TRUE
    )
    names(list) <- paste0("k", c(1, 16, 2, 32, 4, 8))
    
    df <- sapply(
        list,
        as.data.frame,
        simplify = FALSE,
        USE.NAMES = TRUE
    )
    return(df)
}


#  G1 ---------------------------------
path_gtf_G <- "outfiles_gtf-gff3/Trinity-GG/G_N"
files_G <- list.files(
    path_gtf_G,
    pattern = "*.gffread.gff3",
    full.names = TRUE
)
l_G_gtf <- read_in_gtfs(files_G)

files_G_introns_filtered <- list.files(
    path_gtf_G,
    pattern = "*.gffread-intron-filtering-only.gff3",
    full.names = TRUE
)
l_G_gtf_introns_filtered <- read_in_gtfs(files_G_introns_filtered)


#  Q ----------------------------------
path_gtf_Q <- "outfiles_gtf-gff3/Trinity-GG/Q_N"
files_Q <- list.files(
    path_gtf_Q,
    pattern = "*.gffread.gff3",
    full.names = TRUE
)
l_Q_gtf <- read_in_gtfs(files_Q)

files_Q_introns_filtered <- list.files(
    path_gtf_Q,
    pattern = "*.gffread-intron-filtering-only.gff3",
    full.names = TRUE
)
l_Q_gtf_introns_filtered <- read_in_gtfs(files_Q_introns_filtered)


#  Comparisons ------------------------
# l_G_gtf[["k1"]] %>% head()
# l_G_gtf[["k2"]] %>% head()
# 
# l_G_gtf[["k1"]] %>% head()
# l_Q_gtf[["k1"]] %>% head()
# 
# l_Q_gtf[["k1"]] %>% head()
# l_Q_gtf[["k2"]] %>% head()


Read in and process counts matrices

Code

Code: Read in and process counts matrices
#!/usr/bin/env Rscript

#  Initialize functions ---------------
read_in_mat <- function(vector_of_files) {
    out_list <- sapply(
        vector_of_files,
        readr::read_tsv,
        simplify = FALSE,
        USE.NAMES = TRUE
    )
    names(out_list) <- paste0("k", c(1, 16, 2, 32, 4, 8))
    
    return(out_list)
}


rename_columns <- function(list) {
    lapply(
        list,
        function(df) {
            names(df) <- gsub("bams_renamed\\/UT_prim_UMI\\/WT_", "", names(df)) %>%
                gsub("_day1_ovn_", "_", .) %>%
                gsub("_day7_ovn_", "_", .) %>% 
                gsub("_aux-F_tc-F_", "_", .) %>%
                gsub("_tech1\\.UT_prim_UMI\\.bam", "", .) %>%
                gsub("^\\.\\.\\.1", "id", .)
            
            return(df)
        }
    )
}


#  G1 ---------------------------------
path_mat_G <- "outfiles_htseq-count/Trinity-GG/G_N"

files_G_locus <- list.files(
    path_mat_G, pattern = "*-locus.tsv", full.names = TRUE
)
l_G_mat_locus <- read_in_mat(files_G_locus) %>%
    suppressMessages()

files_G_mRNA <- list.files(
    path_mat_G, pattern = "*-mRNA.tsv", full.names = TRUE
)
l_G_mat_mRNA <- read_in_mat(files_G_mRNA) %>%
    suppressMessages()

files_G_exon <- list.files(
    path_mat_G, pattern = "*-exon.tsv", full.names = TRUE
)
l_G_mat_exon <- read_in_mat(files_G_exon) %>%
    suppressMessages()

files_G_CDS <- list.files(
    path_mat_G, pattern = "*-CDS.tsv", full.names = TRUE
)
l_G_mat_CDS <- read_in_mat(files_G_CDS) %>%
    suppressMessages()

files_G_introns_filtered <- list.files(
    path_mat_G,
    pattern = "*.gffread-intron-filtering-only.hc-strd-eq-gene.tsv",
    full.names = TRUE
)
l_G_mat_introns_filtered <- read_in_mat(files_G_introns_filtered) %>%
    suppressMessages()


#  Q ----------------------------------
path_mat_Q <- "outfiles_htseq-count/Trinity-GG/Q_N"

files_Q_locus <- list.files(
    path_mat_Q, pattern = "*-locus.tsv", full.names = TRUE
)
l_Q_mat_locus <- read_in_mat(files_Q_locus) %>%
    suppressMessages()

files_Q_mRNA <- list.files(
    path_mat_Q, pattern = "*-mRNA.tsv", full.names = TRUE
)
l_Q_mat_mRNA <- read_in_mat(files_Q_mRNA) %>%
    suppressMessages()

files_Q_exon <- list.files(
    path_mat_Q, pattern = "*-exon.tsv", full.names = TRUE
)
l_Q_mat_exon <- read_in_mat(files_Q_exon) %>%
    suppressMessages()

files_Q_CDS <- list.files(
    path_mat_Q, pattern = "*-CDS.tsv", full.names = TRUE
)
l_Q_mat_CDS <- read_in_mat(files_Q_CDS) %>%
    suppressMessages()

files_Q_introns_filtered <- list.files(
    path_mat_Q,
    pattern = "*.gffread-intron-filtering-only.hc-strd-eq-gene.tsv",
    full.names = TRUE
)
l_Q_mat_introns_filtered <- read_in_mat(files_Q_introns_filtered) %>%
    suppressMessages()


#  Comparisons ------------------------
# l_Q_mat_sam[["k1"]] %>% head()
# l_Q_mat_sam[["k2"]] %>% head()
# 
# l_Q_mat_sam[["k1"]] %>% head()
# l_Q_mat_rev[["k1"]] %>% head()


#  Rename columns ---------------------
#+ ...in each dataframe composing each list
l_G_mat_locus <- rename_columns(l_G_mat_locus)
l_G_mat_mRNA <- rename_columns(l_G_mat_mRNA)
l_G_mat_exon <- rename_columns(l_G_mat_exon)
l_G_mat_CDS <- rename_columns(l_G_mat_CDS)
l_G_mat_introns_filtered <- rename_columns(l_G_mat_introns_filtered)

l_Q_mat_locus <- rename_columns(l_Q_mat_locus)
l_Q_mat_mRNA <- rename_columns(l_Q_mat_mRNA)
l_Q_mat_exon <- rename_columns(l_Q_mat_exon)
l_Q_mat_CDS <- rename_columns(l_Q_mat_CDS)
l_Q_mat_introns_filtered <- rename_columns(l_Q_mat_introns_filtered)


Categorize putative transcripts/transcript fragments by percentile

Code

Code: Categorize putative transcripts/transcript fragments by percentile
#!/usr/bin/env Rscript

#  Initialize function ----------------
filter_transfrags <- function(x, y) {
    df <- x
    
    if(y == "G1" | y == "G") {
        df <- x[, 1:3] %>% head(., -5)
    } else if(y == "Q") {
        df <- x[, c(1, 6, 7)] %>% head(., -5)
    } else if(y != "G1" | y != "G" | y != "Q") {
        stop("Parameter y must be either 'G1', 'G', or 'Q'")
    }
    
    df[, 4] <- df[, 2] + df[, 3]
    colnames(df)[4] <- "sum"

    ids <- list()

    ids$percentiles <- quantile(
        df$sum,
        probs = c(
            0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50,
            0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95
        )
    ) %>%
        round()
    
    df$below_05 <- ifelse(df$sum <= ids$percentiles[1], TRUE, FALSE)
    df$below_10 <- ifelse(df$sum <= ids$percentiles[2], TRUE, FALSE)
    df$below_15 <- ifelse(df$sum <= ids$percentiles[3], TRUE, FALSE)
    df$below_20 <- ifelse(df$sum <= ids$percentiles[4], TRUE, FALSE)
    df$below_25 <- ifelse(df$sum <= ids$percentiles[5], TRUE, FALSE)
    df$below_30 <- ifelse(df$sum <= ids$percentiles[6], TRUE, FALSE)
    df$below_35 <- ifelse(df$sum <= ids$percentiles[7], TRUE, FALSE)
    df$below_40 <- ifelse(df$sum <= ids$percentiles[8], TRUE, FALSE)
    df$below_45 <- ifelse(df$sum <= ids$percentiles[9], TRUE, FALSE)
    df$below_50 <- ifelse(df$sum <= ids$percentiles[10], TRUE, FALSE)
    df$below_55 <- ifelse(df$sum <= ids$percentiles[11], TRUE, FALSE)
    df$below_60 <- ifelse(df$sum <= ids$percentiles[12], TRUE, FALSE)
    df$below_65 <- ifelse(df$sum <= ids$percentiles[13], TRUE, FALSE)
    df$below_70 <- ifelse(df$sum <= ids$percentiles[14], TRUE, FALSE)
    df$below_75 <- ifelse(df$sum <= ids$percentiles[15], TRUE, FALSE)
    df$below_80 <- ifelse(df$sum <= ids$percentiles[16], TRUE, FALSE)
    df$below_85 <- ifelse(df$sum <= ids$percentiles[17], TRUE, FALSE)
    df$below_90 <- ifelse(df$sum <= ids$percentiles[18], TRUE, FALSE)
    df$below_95 <- ifelse(df$sum <= ids$percentiles[19], TRUE, FALSE)
    
    ids$below_05 <- df[df$below_05 == FALSE, ]$id
    ids$below_10 <- df[df$below_10 == FALSE, ]$id
    ids$below_15 <- df[df$below_15 == FALSE, ]$id
    ids$below_20 <- df[df$below_20 == FALSE, ]$id
    ids$below_25 <- df[df$below_25 == FALSE, ]$id
    ids$below_30 <- df[df$below_30 == FALSE, ]$id
    ids$below_35 <- df[df$below_35 == FALSE, ]$id
    ids$below_40 <- df[df$below_40 == FALSE, ]$id
    ids$below_45 <- df[df$below_45 == FALSE, ]$id
    ids$below_50 <- df[df$below_50 == FALSE, ]$id
    ids$below_55 <- df[df$below_55 == FALSE, ]$id
    ids$below_60 <- df[df$below_60 == FALSE, ]$id
    ids$below_65 <- df[df$below_65 == FALSE, ]$id
    ids$below_70 <- df[df$below_70 == FALSE, ]$id
    ids$below_75 <- df[df$below_75 == FALSE, ]$id
    ids$below_80 <- df[df$below_80 == FALSE, ]$id
    ids$below_85 <- df[df$below_85 == FALSE, ]$id
    ids$below_90 <- df[df$below_90 == FALSE, ]$id
    ids$below_95 <- df[df$below_95 == FALSE, ]$id
    
    return(ids)
}


#  G1 ---------------------------------
f_G_mat_locus <- sapply(
    l_G_mat_locus,
    filter_transfrags,
    simplify = FALSE,
    USE.NAMES = TRUE,
    y = "G1"
)
f_G_mat_mRNA <- sapply(
    l_G_mat_mRNA,
    filter_transfrags,
    simplify = FALSE,
    USE.NAMES = TRUE,
    y = "G1"
)
f_G_mat_exon <- sapply(
    l_G_mat_exon,
    filter_transfrags,
    simplify = FALSE,
    USE.NAMES = TRUE,
    y = "G1"
)
f_G_mat_CDS <- sapply(
    l_G_mat_CDS,
    filter_transfrags,
    simplify = FALSE,
    USE.NAMES = TRUE,
    y = "G1"
)
f_G_mat_introns_filtered <- sapply(
    l_G_mat_introns_filtered,
    filter_transfrags,
    simplify = FALSE,
    USE.NAMES = TRUE,
    y = "G1"
)

#  Q ----------------------------------
f_Q_mat_locus <- sapply(
    l_Q_mat_locus,
    filter_transfrags,
    simplify = FALSE,
    USE.NAMES = TRUE,
    y = "Q"
)
f_Q_mat_mRNA <- sapply(
    l_Q_mat_mRNA,
    filter_transfrags,
    simplify = FALSE,
    USE.NAMES = TRUE,
    y = "Q"
)
f_Q_mat_exon <- sapply(
    l_Q_mat_exon,
    filter_transfrags,
    simplify = FALSE,
    USE.NAMES = TRUE,
    y = "Q"
)
f_Q_mat_CDS <- sapply(
    l_Q_mat_CDS,
    filter_transfrags,
    simplify = FALSE,
    USE.NAMES = TRUE,
    y = "Q"
)
f_Q_mat_introns_filtered <- sapply(
    l_Q_mat_introns_filtered,
    filter_transfrags,
    simplify = FALSE,
    USE.NAMES = TRUE,
    y = "Q"
)


Subset gtf data.frame to retain percentile-filtered gene_ids

Code

Code: Subset gtf data.frame to retain percentile-filtered gene_ids
out$k4
$below_05

$below_10

$below_15

$below_20

$below_25

$below_30

$below_35

$below_40

$below_45

$below_50

$below_55

$below_60

$below_65

$below_70

$below_75

$below_80

$below_85

$below_90

$below_95
NA


Write out processed gtfs

Code

Code: Write out processed gtfs
path_G_mRNA
[1] "outfiles_gtf-gff3/Trinity-GG/G_N/filtered/mRNA"


LS0tCnRpdGxlOiAid29ya19hc3Nlc3NtZW50LXByb2Nlc3NpbmdfZ3Rmc19wYXJ0LTEuUm1kIgphdXRob3I6ICJLQSIKZW1haWw6ICJrYWxhdmF0dEBmcmVkaHV0Y2gub3JnIgpvdXRwdXQ6CiAgICBodG1sX25vdGVib29rOgogICAgICAgIHRvYzogeWVzCiAgICAgICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQo8YnIgLz4KPGJyIC8+CgojIyBFeHBlcmltZW50IGdhbWVwbGFuCiMjIyBUZXh0CjxkZXRhaWxzPgo8c3VtbWFyeT48aT5UZXh0OiBFeHBlcmltZW50IGdhbWVwbGFuPC9pPjwvc3VtbWFyeT4KCjEuIFVzZSBgR2ZmUmVhZGAgdG8gZmlsdGVyIGBUcmluaXR5YC1kZXJpdmVkIGBHTUFQYC1hbGlnbmVkIGBnZmYzYCBmaWxlcy4KMi4gVXNlIH5+YGZlYXR1cmVDb3VudHNgfn4gYGh0c2VxLWNvdW50YCB0byBwZXJmb3JtIGZlYXR1cmUgY291bnRpbmcgd2l0aCByZXNwZWN0IHRvIGB0eXBlYHMgImxvY3VzIiwgIm1STkEiLCAiZXhvbiIsIGFuZCAiQ0RTIiBmZWF0dXJlcyBmcm9tICJiYXNlIiBjYWxscyB0byBgR2ZmUmVhZGAsIGFuZCB3aXRoIHJlc3BlY3QgdG8gYHR5cGVgICJnZW5lIiBmcm9tICJpbnRyb24tZmlsdGVyaW5nLW9ubHkiIGNhbGxzIHRvIGBHZmZSZWFkYC4KMy4gUmVhZCBpbiByZXN1bHRpbmcgY291bnRzIG1hdHJpY2VzIGFuZCBgZ3RmYCBmaWxlcyB1c2luZyBjdXN0b20gYFJgIGNvZGU7IHBlcmZvcm0gcHJvY2Vzc2luZyBhcyBuZWNlc3NhcnkgdXNpbmcgYSBtaXggb2YgYGJpb2NvbmR1Y3RvcmAgYW5kIGB0aWR5dmVyc2VgIHByb2dyYW1zLgo0LiBJbiB0ZXJtcyBvZiByYXcsIG5vbi1ub3JtYWxpemVkIGFsaWdubWVudC10by1wdXRhdGl2ZSB0cmFuc2NyaXB0L3RyYW5zY3JpcHQgZnJhZ21lbnQgKHRyYW5zZnJhZykgdGFsbGllcywgcmV0YWluIHB1dGF0aXZlIHRyYW5zY3JpcHRzL3RyYW5zZnJhZ3Mgd2l0aCB0YWxsaWVzIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byBhIGdpdmVuIHBlcmNlbnRpbGU7IGluIHRoaXMgY2FzZSwgZ2VuZXJhdGUgcmVzdWx0cyBmb3IgdGhlIDV0aCB0byA5NXRoIHBlcmNlbnRpbGVzIGluIGl0ZXJhdGlvbnMgb2YgZml2ZS4KNi4gVXNlIH5+YHJ0cmFja2xheWVyYH5+ICpjdXN0b20gY29kZSogdG8gd3JpdGUgdGhlIGNvbnZlcnRlZCwgY29sbGFwc2VkLCBjb3VudHMtZmlsdGVyZWQgZGF0YSBvYmplY3RzIGFzIGBndGZgIGZpbGVzLgo3LiBTZW5kIHRoZSBwcm9jZXNzZWQgYGd0ZmAgZmlsZXMgdG8gQWxpc29uIEdyZWVubGF3IGZvciBpbnNwZWN0aW9uLgoKRm9yIGJvdGggUSBhbmQgRzEsIEFsaXNvbiBhc2tlZCBtZSB0byBmaWx0ZXIgdGhlIGFzc2VtYmxpZXMgZ2VuZXJhdGVkIHdpdGggYFRyaW5pdHlgIHBhcmFtZXRlciBgbWtjYCA9IDEsIDQsIDguIEhvd2V2ZXIsIGZvciB0aGUgc2FrZSBvZiBjb21wbGV0ZW5lc3MsIGFuZCB0byB1bmRlcnN0YW5kIGNsZWFybHkgd2hhdCAiaW5jb3JyZWN0bmVzcyIgbG9va3MgbGlrZSwgSSB3aWxsIGZpbHRlciBgbWtjYCA9IDIsIDE2LCAzMiBhcyB3ZWxsLiBSZW1lbWJlciB0aGF0IHRoZSBgVHJpbml0eWAgcGFyYW1ldGVycyBgbWlyYCwgYG1nYCwgYW5kIGBnZmAgd2VyZSBoZWxkIGF0IGRlZmF1bHQgbGV2ZWxzIGZvciB0aGUgc3BlY2lmaWMgYXNzZW1ibGllcyB0byBzdXJ2ZXllZCBieSBBbGlzb24uCjwvZGV0YWlscz4KPGJyIC8+CjxiciAvPgoKIyMgQWRkaXRpb25hbCBkZXRhaWxzCiMjIyBUZXh0LCBjb2RlCjxkZXRhaWxzPgo8c3VtbWFyeT48aT5UZXh0LCBjb2RlOiBBZGRpdGlvbmFsIGRldGFpbHM8L2k+PC9zdW1tYXJ5PgoKIyMjIyBJLiBPbiBjYWxsaW5nIGBnZmZyZWFkYApgYGB7YmFzaCwgZXZhbD1GQUxTRX0KIyEvYmluL2Jhc2gKCiMgICJCYXNlIiBjYWxsIHRvIEdmZlJlYWQKZ2ZmcmVhZCBcCiAgICAtdiBcCiAgICAtZyAiJHtmYXN0YV9nfSIgXAogICAgLWkgMTAwMCBcCiAgICAtWiBcCiAgICAtTSAtSyAtUSBcCiAgICAtRiAtTiAtUCBcCiAgICAtLWZvcmNlLWV4b25zIC0tZ2VuZTJleG9uIFwKICAgIC1vICIke291dH0iIFwKICAgIDwoYXdrIC1GICdcdCcgJ0JFR0lOIHtPRlMgPSBGU30geyBnc3ViKC9jaHIvLCAiIiwgJDEpOyBnc3ViKC9NLywgIk1pdG8iLCAkMSk7IHByaW50IH0nICIke2lufSIpIFwKICAgICAgICAgPiA+KHRlZSAtYSAiJHtlcnJfb3V0JS59LnN0ZG91dC50eHQiKSBcCiAgICAgICAgMj4gPih0ZWUgLWEgIiR7ZXJyX291dCUufS5zdGRlcnIudHh0IikKCiMgICJJbnRyb24tZmlsdGVyaW5nLW9ubHkiIGNhbGwgdG8gR2ZmUmVhZAojKyAKIysgTm8gY29sbGFwc2luZywgbWVyZ2luZyB3aXRoIHRoZXNlIGZpbGVzOyBvbmx5IGZpbHRlcmluZyB0byBleGNsdWRlIGV4b25pYwojKyBmZWF0dXJlcyB3aXRoIGludHJvbnMgZ3JlYXRlciB0aGFuIDEwMDAgYnAgaW4gbGVuZ3RoCmdmZnJlYWQgXAogICAgLXYgLU8gXAogICAgLWkgMTAwMCBcCiAgICAtbyAiJHtvdXQvLmdmZjMvLWludHJvbi1maWx0ZXJpbmctb25seS5nZmYzfSIgXAogICAgPChhd2sgLUYgJ1x0JyAnQkVHSU4ge09GUyA9IEZTfSB7IGdzdWIoL2Noci8sICIiLCAkMSk7IGdzdWIoL00vLCAiTWl0byIsICQxKTsgcHJpbnQgfScgIiR7aW59IikgXAogICAgICAgICA+ID4odGVlIC1hICIke2Vycl9vdXQlLn0taW50cm9uLWZpbHRlcmluZy1vbmx5LnN0ZG91dC50eHQiKSBcCiAgICAgICAgMj4gPih0ZWUgLWEgIiR7ZXJyX291dCUufS1pbnRyb24tZmlsdGVyaW5nLW9ubHkuc3RkZXJyLnR4dCIpCmBgYAoKIyMjIyMgTWVhbmluZyBvZiBwYXJhbWV0ZXJzCiMjIyMjIyAiQmFzZSIgY2FsbCB0byBgR2ZmUmVhZGAKLSBgLXZgIGV4cG9zZSAod2FybiBhYm91dCkgZHVwbGljYXRlIHRyYW5zY3JpcHQgSURzIGFuZCBvdGhlciBwb3RlbnRpYWwgcHJvYmxlbXMgd2l0aCB0aGUgZ2l2ZW4gR0ZGL0dURiByZWNvcmRzCi0gYC1nYCBmdWxsIHBhdGggdG8gYSBmYXN0YSBmaWxlIHdpdGggdGhlIGdlbm9taWMgc2VxdWVuY2VzIGZvciBhbGwgaW5wdXQgbWFwcGluZ3MgKG9uZSBwZXIgZ2Vub21pYyBzZXF1ZW5jZSwgd2l0aCBmaWxlIG5hbWVzIG1hdGNoaW5nIHNlcXVlbmNlIG5hbWVzKSAoI05PVEUgaS5lLiwgdGhlIGZhc3RhIC0gZmlsZSBvdXRwdXQgZnJvbSBydW5uaW5nIFRyaW5pdHkgaW4gZ2Vub21lLWd1aWRlZCBtb2RlKQotIGAtaWAgZGlzY2FyZCB0cmFuc2NyaXB0cyBoYXZpbmcgYW4gaW50cm9uIGxhcmdlciB0aGFuIDEwMDAgYnAKLSBgLVpgIG1lcmdlIHZlcnkgY2xvc2UgZXhvbnMgaW50byBhIHNpbmdsZSBleG9uICh3aGVuIGludHJvbiBzaXplPDQpCi0gYC1NYCBjbHVzdGVyIHRoZSBpbnB1dCB0cmFuc2NyaXB0cyBpbnRvIGxvY2ksIGRpc2NhcmRpbmcgInJlZHVuZGFudCIgdHJhbnNjcmlwdHMgKHRob3NlIHdpdGggdGhlIHNhbWUgZXhhY3QgaW50cm9ucyBhbmQgZnVsbHkgY29udGFpbmVkIG9yIGVxdWFsIGJvdW5kYXJpZXMpCi0gYC1LYCBmb3IgdGhlIC1NIG9wdGlvbiwgYWxzbyBkaXNjYXJkIGFzIHJlZHVuZGFudCB0aGUgc2hvcnRlciwgZnVsbHkgY29udGFpbmVkIHRyYW5zY3JpcHRzIChpbnRyb24gY2hhaW5zIG1hdGNoaW5nIGEgcGFydCBvZiB0aGUgY29udGFpbmVyKQotIGAtUWAgZm9yIHRoZSAtTSBvcHRpb24sIG5vIGxvbmdlciByZXF1aXJlIGJvdW5kYXJ5IGNvbnRhaW5tZW50IHdoZW4gYXNzZXNzaW5nIHJlZHVuZGFuY3kgKGNhbiBiZSBjb21iaW5lZCB3aXRoIC1LKTsgb25seSBpbnRyb25zIGhhdmUgdG8gbWF0Y2ggZm9yIG11bHRpLWV4b24gdHJhbnNjcmlwdHMsIGFuZCA+PTgwJSBvdmVybGFwIGZvciBzaW5nbGUtZXhvbiB0cmFuc2NyaXB0cwotIGAtRmAga2VlcCBhbGwgR0ZGIGF0dHJpYnV0ZXMgKGZvciBub24tZXhvbiBmZWF0dXJlcykKLSBgLU5gIGRpc2NhcmQgbXVsdGktZXhvbiBtUk5BcyB0aGF0IGhhdmUgYW55IGludHJvbiB3aXRoIGEgbm9uLWNhbm9uaWNhbCBzcGxpY2Ugc2l0ZSBjb25zZW5zdXMgKGkuZS4sIG5vdCBHVC1BRywgR0MtQUcgb3IgQVQtQUMpCi0gYC1QYCBhZGQgdHJhbnNjcmlwdCBsZXZlbCBHRkYgYXR0cmlidXRlcyBhYm91dCB0aGUgY29kaW5nIHN0YXR1cyBvZiBlYWNoIHRyYW5zY3JpcHQsIGluY2x1ZGluZyBwYXJ0aWFsbmVzcyBvciBpbi1mcmFtZSBzdG9wIGNvZG9ucyAocmVxdWlyZXMgLWcpCi0gYC0tZm9yY2UtZXhvbnNgIG1ha2Ugc3VyZSB0aGF0IHRoZSBsb3dlc3QgbGV2ZWwgR0ZGIGZlYXR1cmVzIGFyZSBjb25zaWRlcmVkICJleG9uIiBmZWF0dXJlcyAoI05PVEUgVGhpcyBpcyBzdGFuZGFyZCBpbiBnZmYzIGFuZCBndGYgZmlsZXMpCi0gYC1vYCB3cml0ZSB0aGUgb3V0cHV0IHJlY29yZHMgaW50byA8b3V0ZmlsZT4gaW5zdGVhZCBvZiBzdGRvdXQKCiMjIyMjIyAiSW50cm9uLWZpbHRlcmluZy1vbmx5IiBjYWxsIHRvIGBHZmZSZWFkYAotIGAtdmAgZXhwb3NlICh3YXJuIGFib3V0KSBkdXBsaWNhdGUgdHJhbnNjcmlwdCBJRHMgYW5kIG90aGVyIHBvdGVudGlhbCBwcm9ibGVtcyB3aXRoIHRoZSBnaXZlbiBHRkYvR1RGIHJlY29yZHMKLSBgLU9gIHByb2Nlc3Mgb3RoZXIgbm9uLXRyYW5zY3JpcHQgR0ZGIHJlY29yZHMgKGJ5IGRlZmF1bHQgbm9uLXRyYW5zY3JpcHQgcmVjb3JkcyBhcmUgaWdub3JlZCkgKGAjTk9URWAgVGhpcyBrZWVwcyAnZ2VuZScgZmVhdHVyZXMgKG91dHB1dCBieSBnbWFwKSBpbiB0aGUgZ2ZmMy9ndGYsIGFsdGhvdWdoICJnZW5lIiBpcyBleGFjdGx5IHRoZSBzYW1lIGFzICJtUk5BIiBhcyBvdXRwdXQgYnkgZ21hcCkKLSBgLWlgIGRpc2NhcmQgdHJhbnNjcmlwdHMgaGF2aW5nIGFuIGludHJvbiBsYXJnZXIgdGhhbiAxMDAwIGJwCi0gYC1vYCB3cml0ZSB0aGUgb3V0cHV0IHJlY29yZHMgaW50byA8b3V0ZmlsZT4gaW5zdGVhZCBvZiBzdGRvdXQKPGJyIC8+CgojIyMjIElJLiBPbiBjYWxsaW5nIGBodHNlcS1jb3VudGAKIyMjIyMgLi4ud2l0aCByZXNwZWN0IHRvIGB0eXBlYCAibG9jdXMiCkFzIGEgcmVzdWx0IG9mIGNhbGxpbmcgZ2ZmcmVhZCB3aXRoIHRoZSBgLVpgIGAtTWAgYC1LYCBhbmQgYC1RYCBhcmd1bWVudHMsIGEgbmV3IGZlYXR1cmUgaXMgYWRkZWQgdG8gdGhlIGdmZjMvZ3RmIGZpbGVzOiAibG9jdXMiLiAibG9jdXMiIGlzIGEgcHV0YXRpdmUgcGFyZW50IGZlYXR1cmUgbWFkZSBmcm9tIGNvbGxhcHNpbmcgYW5kIGpvaW5pbmcgImNoaWxkcmVuIiBmZWF0dXJlcyAoaGllcmFyY2hpY2FsbHksICJtUk5BIiBhbmQgImV4b24iKSBhcyBkZXNjcmliZWQgZm9yIGAtWmAgYC1NYCBgLUtgIGFuZCBgLVFgLiBUaGlzIGlzIGFuIGV4dGVuc2lvbiBvZiB0aGUga2luZCBvZiBjb2xsYXBzaW5nIHBlcmZvcm1lZCBieSBgZ2ZmY29tcGFyZSAtQ2AuIFRodXMsIGNvdW50cyBtYXRyaWNlcyB3ZXJlIGNyZWF0ZWQgd2l0aCByZXNwZWN0IHRvIHRoZXNlICJsb2N1cyIgZmVhdHVyZXMuCgpgYGB7YmFzaCwgZXZhbD1GQUxTRX0KIyEvYmluL2Jhc2gKCnNiYXRjaCBcCiAgICAtLWpvYi1uYW1lPSJodHNlcS1jb3VudC1sb2N1cyIgXAogICAgLS1ub2Rlcz0xIFwKICAgIC0tY3B1cy1wZXItdGFzaz04IFwKICAgIC0tZXJyb3I9IiR7ZXJyX291dH0tbG9jdXMuJUEuc3RkZXJyLnR4dCIgXAogICAgLS1vdXRwdXQ9IiR7ZXJyX291dH0tbG9jdXMuJUEuc3Rkb3V0LnR4dCIgXAogICAgaHRzZXEtY291bnQgXAogICAgICAgIC0tb3JkZXIgInBvcyIgXAogICAgICAgIC0tc3RyYW5kZWQgIiR7aGNfc3RyZH0iIFwKICAgICAgICAtLW5vbnVuaXF1ZSAiYWxsIiBcCiAgICAgICAgLS10eXBlICJsb2N1cyIgXAogICAgICAgIC0taWRhdHRyICJJRCIgXAogICAgICAgIC0tbnByb2Nlc3NlcyA4IFwKICAgICAgICAtLWNvdW50c19vdXRwdXQgIiR7b3V0Ly50c3YvLWxvY3VzLnRzdn0iIFwKICAgICAgICAtLXdpdGgtaGVhZGVyIFwKICAgICAgICAke2JhbXNbKl19IFwKICAgICAgICAiJHtpbn0iCmBgYAoKIyMjIyMgLi4ud2l0aCByZXNwZWN0IHRvIGB0eXBlYCAibVJOQSIKQ3JlYXRlIHRoZSBjb3VudHMgbWF0cml4IGJ5IGxvb2tpbmcgYXQgY2hpbGRyZW4gIm1STkEiIGZlYXR1cmVzIHJhdGhlciB0aGFuIHBhcmVudCAibG9jdXMiIGZlYXR1cmVzLiBUaGlzIGlzIHRoZSBraW5kIG9mIGNvbGxhcHNpbmcgcGVyZm9ybWVkIGJ5IGBnZmZjb21wYXJlIC1DYC4KCmBgYHtiYXNoLCBldmFsPUZBTFNFfQojIS9iaW4vYmFzaAoKc2JhdGNoIFwKICAgIC0tam9iLW5hbWU9Imh0c2VxLWNvdW50LW1STkEiIFwKICAgIC0tbm9kZXM9MSBcCiAgICAtLWNwdXMtcGVyLXRhc2s9OCBcCiAgICAtLWVycm9yPSIke2Vycl9vdXR9LW1STkEuJUEuc3RkZXJyLnR4dCIgXAogICAgLS1vdXRwdXQ9IiR7ZXJyX291dH0tbVJOQS4lQS5zdGRvdXQudHh0IiBcCiAgICBodHNlcS1jb3VudCBcCiAgICAgICAgLS1vcmRlciAicG9zIiBcCiAgICAgICAgLS1zdHJhbmRlZCAiJHtoY19zdHJkfSIgXAogICAgICAgIC0tbm9udW5pcXVlICJhbGwiIFwKICAgICAgICAtLXR5cGUgIm1STkEiIFwKICAgICAgICAtLWlkYXR0ciAiSUQiIFwKICAgICAgICAtLW5wcm9jZXNzZXMgOCBcCiAgICAgICAgLS1jb3VudHNfb3V0cHV0ICIke291dC8udHN2Ly1tUk5BLnRzdn0iIFwKICAgICAgICAtLXdpdGgtaGVhZGVyIFwKICAgICAgICAke2JhbXNbKl19IFwKICAgICAgICAiJHtpbn0iCmBgYAoKIyMjIyMgLi4ud2l0aCByZXNwZWN0IHRvIGB0eXBlYCAiZXhvbiIKQ3JlYXRlIHRoZSBjb3VudHMgbWF0cml4IGJ5IGxvb2tpbmcgYXQgY2hpbGRyZW4gImV4b24iIGZlYXR1cmVzLgoKYGBge2Jhc2gsIGV2YWw9RkFMU0V9CiMhL2Jpbi9iYXNoCgpzYmF0Y2ggXAogICAgLS1qb2ItbmFtZT0iaHRzZXEtY291bnQtZXhvbiIgXAogICAgLS1ub2Rlcz0xIFwKICAgIC0tY3B1cy1wZXItdGFzaz04IFwKICAgIC0tZXJyb3I9IiR7ZXJyX291dH0tZXhvbi4lQS5zdGRlcnIudHh0IiBcCiAgICAtLW91dHB1dD0iJHtlcnJfb3V0fS1leG9uLiVBLnN0ZG91dC50eHQiIFwKICAgIGh0c2VxLWNvdW50IFwKICAgICAgICAtLW9yZGVyICJwb3MiIFwKICAgICAgICAtLXN0cmFuZGVkICIke2hjX3N0cmR9IiBcCiAgICAgICAgLS1ub251bmlxdWUgImFsbCIgXAogICAgICAgIC0tdHlwZSAiZXhvbiIgXAogICAgICAgIC0taWRhdHRyICJQYXJlbnQiIFwKICAgICAgICAtLW5wcm9jZXNzZXMgOCBcCiAgICAgICAgLS1jb3VudHNfb3V0cHV0ICIke291dC8udHN2Ly1leG9uLnRzdn0iIFwKICAgICAgICAtLXdpdGgtaGVhZGVyIFwKICAgICAgICAke2JhbXNbKl19IFwKICAgICAgICAiJHtpbn0iCmBgYAoKIyMjIyMgLi4ud2l0aCByZXNwZWN0IHRvIGB0eXBlYCAiQ0RTIgpgZ2ZmcmVhZGAgc2NhbnMgdGhlIGBmYXN0YWBzIHN1cHBsaWVkIGAtZ2AgYW5kIHJvdWdobHkgZXN0aW1hdGVzIHN0YXJ0IGFuZCBzdG9wIGNvZG9ucyBmcm9tIHRoZSBudCBzZXF1ZW5jZXM7IGl0IHRoZW4gYWRkcyB0aGVzZSBDRFMgZXN0aW1hdGVzIHRvIHRoZSBgZ2ZmM2AvYGd0ZmAgZmlsZXMuIENyZWF0ZSB0aGUgY291bnRzIG1hdHJpeCBieSBsb29raW5nIGF0IHRoZXNlIGVzdGltYXRlZCAiQ0RTIiBmZWF0dXJlcy4KCmBgYHtiYXNoLCBldmFsPUZBTFNFfQojIS9iaW4vYmFzaAoKc2JhdGNoIFwKICAgIC0tam9iLW5hbWU9Imh0c2VxLWNvdW50LUNEUyIgXAogICAgLS1ub2Rlcz0xIFwKICAgIC0tY3B1cy1wZXItdGFzaz04IFwKICAgIC0tZXJyb3I9IiR7ZXJyX291dH0tQ0RTLiVBLnN0ZGVyci50eHQiIFwKICAgIC0tb3V0cHV0PSIke2Vycl9vdXR9LUNEUy4lQS5zdGRvdXQudHh0IiBcCiAgICBodHNlcS1jb3VudCBcCiAgICAgICAgLS1vcmRlciAicG9zIiBcCiAgICAgICAgLS1zdHJhbmRlZCAiJHtoY19zdHJkfSIgXAogICAgICAgIC0tbm9udW5pcXVlICJhbGwiIFwKICAgICAgICAtLXR5cGUgIkNEUyIgXAogICAgICAgIC0taWRhdHRyICJQYXJlbnQiIFwKICAgICAgICAtLW5wcm9jZXNzZXMgOCBcCiAgICAgICAgLS1jb3VudHNfb3V0cHV0ICIke291dC8udHN2Ly1DRFMudHN2fSIgXAogICAgICAgIC0td2l0aC1oZWFkZXIgXAogICAgICAgICR7YmFtc1sqXX0gXAogICAgICAgICIke2lufSIKYGBgCgojIyMjIyAuLi53aXRoIHJlc3BlY3QgdG8gYHR5cGVgICJnZW5lIiAoImludHJvbi1vbmx5LWZpbHRlcmluZyIgY2FsbCB0byBgR2ZmUmVhZGApCkNyZWF0ZSB0aGUgY291bnRzIG1hdHJpeCBieSBsb29raW5nIGF0IHBhcmVudCAiZ2VuZSIgZmVhdHVyZXMgZnJvbSB0aGUgZmlsZXMgb3V0cHV0IGluIHNlY3Rpb24gPGI+Ik9uIGNhbGxpbmcgYGdmZnJlYWRgIjwvYj4gYWJvdmUuCgpgYGB7YmFzaCwgZXZhbD1GQUxTRX0KIyEvYmluL2Jhc2gKc2JhdGNoIFwKICAgIC0tam9iLW5hbWU9Imh0c2VxLWNvdW50LWdlbmUiIFwKICAgIC0tbm9kZXM9MSBcCiAgICAtLWNwdXMtcGVyLXRhc2s9OCBcCiAgICAtLWVycm9yPSIke2Vycl9vdXR9LWdlbmUuJUEuc3RkZXJyLnR4dCIgXAogICAgLS1vdXRwdXQ9IiR7ZXJyX291dH0tZ2VuZS4lQS5zdGRvdXQudHh0IiBcCiAgICBodHNlcS1jb3VudCBcCiAgICAgICAgLS1vcmRlciAicG9zIiBcCiAgICAgICAgLS1zdHJhbmRlZCAiJHtoY19zdHJkfSIgXAogICAgICAgIC0tbm9udW5pcXVlICJhbGwiIFwKICAgICAgICAtLXR5cGUgImdlbmUiIFwKICAgICAgICAtLWlkYXR0ciAiSUQiIFwKICAgICAgICAtLW5wcm9jZXNzZXMgOCBcCiAgICAgICAgLS1jb3VudHNfb3V0cHV0ICIke291dC8udHN2Ly1nZW5lLnRzdn0iIFwKICAgICAgICAtLXdpdGgtaGVhZGVyIFwKICAgICAgICAke2JhbXNbKl19IFwKICAgICAgICAiJHtpbn0iCmBgYAo8YnIgLz4KCiMjIyMgSUlJLiBUaGUgZ2VuZXJhbCB3b3JrZmxvdyBmb3IgbWFraW5nIHRoZSBmaWx0ZXJlZCBndGZzCjEuIFJlYWQgaW4gYW5kIHByb2Nlc3MgYGd0ZmAvYGdmZjNgIGZpbGVzIChhcyBkYXRhZnJhbWVzKQoyLiBSZWFkIGluIGFuZCBwcm9jZXNzIGNvdW50cyBtYXRyaWNlczogImxvY3VzIiwgIm1STkEiLCAiZXhvbiIsICJDRFMiLCBhbmQgImdlbmUiIChpbnRyb24tb25seS1maWx0ZXJpbmcpCjMuIENhdGVnb3JpemUgcHV0YXRpdmUgdHJhbnNjcmlwdHMvdHJhbnNmcmFncyBieSBwZXJjZW50aWxlOiBmcm9tIHBlcmNlbnRpbGUgNSB0byBwZXJjZW50aWxlIDk1IGluIHN0ZXBzIG9mIDUKNC4gU3Vic2V0IGRhdGFmcmFtZXMgdG8gcmV0YWluIHBlcmNlbnRpbGUtZmlsdGVyZWQgSURzOiAibG9jdXMiLCAibVJOQSIsICJleG9uIiwgIkNEUyIsIGFuZCAiZ2VuZSIgKGludHJvbi1vbmx5LWZpbHRlcmluZykKNS4gV3JpdGUgb3V0IHByb2Nlc3NlZCBgZ3RmYHMKPGJyIC8+CgojIyMjIElWLiBDb3B5aW5nIG92ZXIgZmlsZXMgdG8gQWxpc29uCmBgYHtiYXNoLCBldmFsPUZBTFNFfQojIS9iaW4vYmFzaAoKbWtkaXIgLXAgL2hvbWUva2FsYXZhdHQvdHN1a2l5YW1hbGFiL2FsaXNvbmcvS0EuZ3Rmc19xdWFudGlsZS1maWx0ZXJlZF9UcmluaXR5LUdHX0cxLVFfMjAyMy0wNDEwL3tndGYtZ2ZmMyx0c3Z9CiMgbWtkaXI6IGNyZWF0ZWQgZGlyZWN0b3J5ICcvaG9tZS9rYWxhdmF0dC90c3VraXlhbWFsYWIvYWxpc29uZy9LQS5ndGZzX3F1YW50aWxlLWZpbHRlcmVkX1RyaW5pdHktR0dfRzEtUV8yMDIzLTA0MTAnCiMgbWtkaXI6IGNyZWF0ZWQgZGlyZWN0b3J5ICcvaG9tZS9rYWxhdmF0dC90c3VraXlhbWFsYWIvYWxpc29uZy9LQS5ndGZzX3F1YW50aWxlLWZpbHRlcmVkX1RyaW5pdHktR0dfRzEtUV8yMDIzLTA0MTAvZ3RmLWdmZjMnCiMgbWtkaXI6IGNyZWF0ZWQgZGlyZWN0b3J5ICcvaG9tZS9rYWxhdmF0dC90c3VraXlhbWFsYWIvYWxpc29uZy9LQS5ndGZzX3F1YW50aWxlLWZpbHRlcmVkX1RyaW5pdHktR0dfRzEtUV8yMDIzLTA0MTAvdHN2JwoKY2QgL2hvbWUva2FsYXZhdHQvdHN1a2l5YW1hbGFiL2thbGF2YXR0LzIwMjJfdHJhbnNjcmlwdG9tZS1jb25zdHJ1Y3Rpb24vcmVzdWx0cy8yMDIzLTAyMTUKCmNwIC1yIFwKICAgIG91dGZpbGVzX2d0Zi1nZmYzL1RyaW5pdHktR0cgXAogICAgL2hvbWUva2FsYXZhdHQvdHN1a2l5YW1hbGFiL2FsaXNvbmcvS0EuZ3Rmc19xdWFudGlsZS1maWx0ZXJlZF9UcmluaXR5LUdHX0cxLVFfMjAyMy0wNDEwL2d0Zi1nZmYzCgpjcCAtciBcCiAgICBvdXRmaWxlc19odHNlcS1jb3VudC9UcmluaXR5LUdHIFwKICAgIC9ob21lL2thbGF2YXR0L3RzdWtpeWFtYWxhYi9hbGlzb25nL0tBLmd0ZnNfcXVhbnRpbGUtZmlsdGVyZWRfVHJpbml0eS1HR19HMS1RXzIwMjMtMDQxMC90c3YKCiMgIE1hbnVhbGx5IGNvcHlpbmcgaW4gdGhlICdmaWx0ZXJlZC8nIHN1YmRpcmVjdG9yaWVzIGZyb20gbG9jYWwgdG8gcmVtb3RlCmBgYAo8L2RldGFpbHM+CjxiciAvPgo8YnIgLz4KCiMjIDAmbmRhc2g7Mi4gQ29tbWFuZC1saW5lIHdvcmsKU2VlIFtgd29ya19hc3Nlc3NtZW50LXByb2Nlc3NpbmdfZ3Rmc19wYXJ0LTAubWRgXSguL3dvcmtfYXNzZXNzbWVudC1wcm9jZXNzaW5nX2d0ZnNfcGFydC0wLm1kKSwgd2hlcmUgKnN0ZXBzIDAgdGhyb3VnaCAzKiBhcmUgZGV0YWlsZWQuIEJlbG93LCB3ZSBwaWNrIHVwIHdpdGggKnN0ZXAgNCouCjxiciAvPgo8YnIgLz4KCiMjIDMuIFBlcmZvcm0gcXVhbnRpbGUgZmlsdGVyaW5nIG9mIHB1dGF0aXZlIHRyYW5zY3JpcHRzL3RyYW5zZnJhZ3MKIyMjIEdldCBzaXR1YXRlZAojIyMjIENvZGUKPGRldGFpbHM+CjxzdW1tYXJ5PjxpPkNvZGU6IEdldCBzaXR1YXRlZDwvaT48L3N1bW1hcnk+CgpgI1NUQVJUYApgYGB7cn0KIyEvdXNyL2Jpbi9lbnYgUnNjcmlwdAoKbGlicmFyeShHZW5vbWljUmFuZ2VzKQpsaWJyYXJ5KElSYW5nZXMpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KHJ0cmFja2xheWVyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKCm9wdGlvbnMoc2NpcGVuID0gOTk5KQpvcHRpb25zKGdncmVwZWwubWF4Lm92ZXJsYXBzID0gSW5mKQoKaWYoc3RyaW5ncjo6c3RyX2RldGVjdChnZXR3ZCgpLCAia2FsYXZhdHRhbSIpKSB7CiAgICBwX2xvY2FsIDwtICIvVXNlcnMva2FsYXZhdHRhbS9Ecm9wYm94L0ZIQ0MiCn0gZWxzZSB7CiAgICBwX2xvY2FsIDwtICIvVXNlcnMva2FsYXZhdHQvcHJvamVjdHMtZXRjIgp9CnBfd2QgPC0gIjIwMjJfdHJhbnNjcmlwdG9tZS1jb25zdHJ1Y3Rpb24vcmVzdWx0cy8yMDIzLTAyMTUiCgpzZXR3ZChwYXN0ZShwX2xvY2FsLCBwX3dkLCBzZXAgPSAiLyIpKQpnZXR3ZCgpCgpybShwX2xvY2FsLCBwX3dkKQpgYGAKPC9kZXRhaWxzPgo8YnIgLz4KCiMjIyBSZWFkIGluIGFuZCBwcm9jZXNzIGBndGZgIGZpbGVzIChhcyBgZGF0YS5mcmFtZWBzKQojIyMjIENvZGUKPGRldGFpbHM+CjxzdW1tYXJ5PjxpPkNvZGU6IFJlYWQgaW4gYW5kIHByb2Nlc3MgYGd0ZmAgZmlsZXMgKGFzIGBkYXRhLmZyYW1lYHMpPC9pPjwvc3VtbWFyeT4KCmBgYHtyfQojIS91c3IvYmluL2VudiBSc2NyaXB0CgojICBJbml0aWFsaXplIGZ1bmN0aW9ucyAtLS0tLS0tLS0tLS0tLS0KaW1wb3J0X2cgPC0gZnVuY3Rpb24oZmlsZSkgewogICAgcnRyYWNrbGF5ZXI6OmltcG9ydChmaWxlKQp9CgoKcmVhZF9pbl9ndGZzIDwtIGZ1bmN0aW9uKHZlY3Rvcl9maWxlcykgewogICAgbGlzdCA8LSBzYXBwbHkoCiAgICAgICAgdmVjdG9yX2ZpbGVzLAogICAgICAgIGltcG9ydF9nLAogICAgICAgIHNpbXBsaWZ5ID0gRkFMU0UsCiAgICAgICAgVVNFLk5BTUVTID0gVFJVRQogICAgKQogICAgbmFtZXMobGlzdCkgPC0gcGFzdGUwKCJrIiwgYygxLCAxNiwgMiwgMzIsIDQsIDgpKQogICAgCiAgICBkZiA8LSBzYXBwbHkoCiAgICAgICAgbGlzdCwKICAgICAgICBhcy5kYXRhLmZyYW1lLAogICAgICAgIHNpbXBsaWZ5ID0gRkFMU0UsCiAgICAgICAgVVNFLk5BTUVTID0gVFJVRQogICAgKQogICAgcmV0dXJuKGRmKQp9CgoKIyAgRzEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnBhdGhfZ3RmX0cgPC0gIm91dGZpbGVzX2d0Zi1nZmYzL1RyaW5pdHktR0cvR19OIgpmaWxlc19HIDwtIGxpc3QuZmlsZXMoCiAgICBwYXRoX2d0Zl9HLAogICAgcGF0dGVybiA9ICIqLmdmZnJlYWQuZ2ZmMyIsCiAgICBmdWxsLm5hbWVzID0gVFJVRQopCmxfR19ndGYgPC0gcmVhZF9pbl9ndGZzKGZpbGVzX0cpCgpmaWxlc19HX2ludHJvbnNfZmlsdGVyZWQgPC0gbGlzdC5maWxlcygKICAgIHBhdGhfZ3RmX0csCiAgICBwYXR0ZXJuID0gIiouZ2ZmcmVhZC1pbnRyb24tZmlsdGVyaW5nLW9ubHkuZ2ZmMyIsCiAgICBmdWxsLm5hbWVzID0gVFJVRQopCmxfR19ndGZfaW50cm9uc19maWx0ZXJlZCA8LSByZWFkX2luX2d0ZnMoZmlsZXNfR19pbnRyb25zX2ZpbHRlcmVkKQoKCiMgIFEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpwYXRoX2d0Zl9RIDwtICJvdXRmaWxlc19ndGYtZ2ZmMy9UcmluaXR5LUdHL1FfTiIKZmlsZXNfUSA8LSBsaXN0LmZpbGVzKAogICAgcGF0aF9ndGZfUSwKICAgIHBhdHRlcm4gPSAiKi5nZmZyZWFkLmdmZjMiLAogICAgZnVsbC5uYW1lcyA9IFRSVUUKKQpsX1FfZ3RmIDwtIHJlYWRfaW5fZ3RmcyhmaWxlc19RKQoKZmlsZXNfUV9pbnRyb25zX2ZpbHRlcmVkIDwtIGxpc3QuZmlsZXMoCiAgICBwYXRoX2d0Zl9RLAogICAgcGF0dGVybiA9ICIqLmdmZnJlYWQtaW50cm9uLWZpbHRlcmluZy1vbmx5LmdmZjMiLAogICAgZnVsbC5uYW1lcyA9IFRSVUUKKQpsX1FfZ3RmX2ludHJvbnNfZmlsdGVyZWQgPC0gcmVhZF9pbl9ndGZzKGZpbGVzX1FfaW50cm9uc19maWx0ZXJlZCkKCgojICBDb21wYXJpc29ucyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBsX0dfZ3RmW1siazEiXV0gJT4lIGhlYWQoKQojIGxfR19ndGZbWyJrMiJdXSAlPiUgaGVhZCgpCiMgCiMgbF9HX2d0ZltbImsxIl1dICU+JSBoZWFkKCkKIyBsX1FfZ3RmW1siazEiXV0gJT4lIGhlYWQoKQojIAojIGxfUV9ndGZbWyJrMSJdXSAlPiUgaGVhZCgpCiMgbF9RX2d0ZltbImsyIl1dICU+JSBoZWFkKCkKYGBgCjwvZGV0YWlscz4KPGJyIC8+CgojIyMgUmVhZCBpbiBhbmQgcHJvY2VzcyBjb3VudHMgbWF0cmljZXMKIyMjIyBDb2RlCjxkZXRhaWxzPgo8c3VtbWFyeT48aT5Db2RlOiBSZWFkIGluIGFuZCBwcm9jZXNzIGNvdW50cyBtYXRyaWNlczwvaT48L3N1bW1hcnk+CgpgYGB7cn0KIyEvdXNyL2Jpbi9lbnYgUnNjcmlwdAoKIyAgSW5pdGlhbGl6ZSBmdW5jdGlvbnMgLS0tLS0tLS0tLS0tLS0tCnJlYWRfaW5fbWF0IDwtIGZ1bmN0aW9uKHZlY3Rvcl9vZl9maWxlcykgewogICAgb3V0X2xpc3QgPC0gc2FwcGx5KAogICAgICAgIHZlY3Rvcl9vZl9maWxlcywKICAgICAgICByZWFkcjo6cmVhZF90c3YsCiAgICAgICAgc2ltcGxpZnkgPSBGQUxTRSwKICAgICAgICBVU0UuTkFNRVMgPSBUUlVFCiAgICApCiAgICBuYW1lcyhvdXRfbGlzdCkgPC0gcGFzdGUwKCJrIiwgYygxLCAxNiwgMiwgMzIsIDQsIDgpKQogICAgCiAgICByZXR1cm4ob3V0X2xpc3QpCn0KCgpyZW5hbWVfY29sdW1ucyA8LSBmdW5jdGlvbihsaXN0KSB7CiAgICBsYXBwbHkoCiAgICAgICAgbGlzdCwKICAgICAgICBmdW5jdGlvbihkZikgewogICAgICAgICAgICBuYW1lcyhkZikgPC0gZ3N1YigiYmFtc19yZW5hbWVkXFwvVVRfcHJpbV9VTUlcXC9XVF8iLCAiIiwgbmFtZXMoZGYpKSAlPiUKICAgICAgICAgICAgICAgIGdzdWIoIl9kYXkxX292bl8iLCAiXyIsIC4pICU+JQogICAgICAgICAgICAgICAgZ3N1YigiX2RheTdfb3ZuXyIsICJfIiwgLikgJT4lIAogICAgICAgICAgICAgICAgZ3N1YigiX2F1eC1GX3RjLUZfIiwgIl8iLCAuKSAlPiUKICAgICAgICAgICAgICAgIGdzdWIoIl90ZWNoMVxcLlVUX3ByaW1fVU1JXFwuYmFtIiwgIiIsIC4pICU+JQogICAgICAgICAgICAgICAgZ3N1YigiXlxcLlxcLlxcLjEiLCAiaWQiLCAuKQogICAgICAgICAgICAKICAgICAgICAgICAgcmV0dXJuKGRmKQogICAgICAgIH0KICAgICkKfQoKCiMgIEcxIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpwYXRoX21hdF9HIDwtICJvdXRmaWxlc19odHNlcS1jb3VudC9UcmluaXR5LUdHL0dfTiIKCmZpbGVzX0dfbG9jdXMgPC0gbGlzdC5maWxlcygKICAgIHBhdGhfbWF0X0csIHBhdHRlcm4gPSAiKi1sb2N1cy50c3YiLCBmdWxsLm5hbWVzID0gVFJVRQopCmxfR19tYXRfbG9jdXMgPC0gcmVhZF9pbl9tYXQoZmlsZXNfR19sb2N1cykgJT4lCiAgICBzdXBwcmVzc01lc3NhZ2VzKCkKCmZpbGVzX0dfbVJOQSA8LSBsaXN0LmZpbGVzKAogICAgcGF0aF9tYXRfRywgcGF0dGVybiA9ICIqLW1STkEudHN2IiwgZnVsbC5uYW1lcyA9IFRSVUUKKQpsX0dfbWF0X21STkEgPC0gcmVhZF9pbl9tYXQoZmlsZXNfR19tUk5BKSAlPiUKICAgIHN1cHByZXNzTWVzc2FnZXMoKQoKZmlsZXNfR19leG9uIDwtIGxpc3QuZmlsZXMoCiAgICBwYXRoX21hdF9HLCBwYXR0ZXJuID0gIiotZXhvbi50c3YiLCBmdWxsLm5hbWVzID0gVFJVRQopCmxfR19tYXRfZXhvbiA8LSByZWFkX2luX21hdChmaWxlc19HX2V4b24pICU+JQogICAgc3VwcHJlc3NNZXNzYWdlcygpCgpmaWxlc19HX0NEUyA8LSBsaXN0LmZpbGVzKAogICAgcGF0aF9tYXRfRywgcGF0dGVybiA9ICIqLUNEUy50c3YiLCBmdWxsLm5hbWVzID0gVFJVRQopCmxfR19tYXRfQ0RTIDwtIHJlYWRfaW5fbWF0KGZpbGVzX0dfQ0RTKSAlPiUKICAgIHN1cHByZXNzTWVzc2FnZXMoKQoKZmlsZXNfR19pbnRyb25zX2ZpbHRlcmVkIDwtIGxpc3QuZmlsZXMoCiAgICBwYXRoX21hdF9HLAogICAgcGF0dGVybiA9ICIqLmdmZnJlYWQtaW50cm9uLWZpbHRlcmluZy1vbmx5LmhjLXN0cmQtZXEtZ2VuZS50c3YiLAogICAgZnVsbC5uYW1lcyA9IFRSVUUKKQpsX0dfbWF0X2ludHJvbnNfZmlsdGVyZWQgPC0gcmVhZF9pbl9tYXQoZmlsZXNfR19pbnRyb25zX2ZpbHRlcmVkKSAlPiUKICAgIHN1cHByZXNzTWVzc2FnZXMoKQoKCiMgIFEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpwYXRoX21hdF9RIDwtICJvdXRmaWxlc19odHNlcS1jb3VudC9UcmluaXR5LUdHL1FfTiIKCmZpbGVzX1FfbG9jdXMgPC0gbGlzdC5maWxlcygKICAgIHBhdGhfbWF0X1EsIHBhdHRlcm4gPSAiKi1sb2N1cy50c3YiLCBmdWxsLm5hbWVzID0gVFJVRQopCmxfUV9tYXRfbG9jdXMgPC0gcmVhZF9pbl9tYXQoZmlsZXNfUV9sb2N1cykgJT4lCiAgICBzdXBwcmVzc01lc3NhZ2VzKCkKCmZpbGVzX1FfbVJOQSA8LSBsaXN0LmZpbGVzKAogICAgcGF0aF9tYXRfUSwgcGF0dGVybiA9ICIqLW1STkEudHN2IiwgZnVsbC5uYW1lcyA9IFRSVUUKKQpsX1FfbWF0X21STkEgPC0gcmVhZF9pbl9tYXQoZmlsZXNfUV9tUk5BKSAlPiUKICAgIHN1cHByZXNzTWVzc2FnZXMoKQoKZmlsZXNfUV9leG9uIDwtIGxpc3QuZmlsZXMoCiAgICBwYXRoX21hdF9RLCBwYXR0ZXJuID0gIiotZXhvbi50c3YiLCBmdWxsLm5hbWVzID0gVFJVRQopCmxfUV9tYXRfZXhvbiA8LSByZWFkX2luX21hdChmaWxlc19RX2V4b24pICU+JQogICAgc3VwcHJlc3NNZXNzYWdlcygpCgpmaWxlc19RX0NEUyA8LSBsaXN0LmZpbGVzKAogICAgcGF0aF9tYXRfUSwgcGF0dGVybiA9ICIqLUNEUy50c3YiLCBmdWxsLm5hbWVzID0gVFJVRQopCmxfUV9tYXRfQ0RTIDwtIHJlYWRfaW5fbWF0KGZpbGVzX1FfQ0RTKSAlPiUKICAgIHN1cHByZXNzTWVzc2FnZXMoKQoKZmlsZXNfUV9pbnRyb25zX2ZpbHRlcmVkIDwtIGxpc3QuZmlsZXMoCiAgICBwYXRoX21hdF9RLAogICAgcGF0dGVybiA9ICIqLmdmZnJlYWQtaW50cm9uLWZpbHRlcmluZy1vbmx5LmhjLXN0cmQtZXEtZ2VuZS50c3YiLAogICAgZnVsbC5uYW1lcyA9IFRSVUUKKQpsX1FfbWF0X2ludHJvbnNfZmlsdGVyZWQgPC0gcmVhZF9pbl9tYXQoZmlsZXNfUV9pbnRyb25zX2ZpbHRlcmVkKSAlPiUKICAgIHN1cHByZXNzTWVzc2FnZXMoKQoKCiMgIENvbXBhcmlzb25zIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIGxfUV9tYXRfc2FtW1siazEiXV0gJT4lIGhlYWQoKQojIGxfUV9tYXRfc2FtW1siazIiXV0gJT4lIGhlYWQoKQojIAojIGxfUV9tYXRfc2FtW1siazEiXV0gJT4lIGhlYWQoKQojIGxfUV9tYXRfcmV2W1siazEiXV0gJT4lIGhlYWQoKQoKCiMgIFJlbmFtZSBjb2x1bW5zIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQojKyAuLi5pbiBlYWNoIGRhdGFmcmFtZSBjb21wb3NpbmcgZWFjaCBsaXN0CmxfR19tYXRfbG9jdXMgPC0gcmVuYW1lX2NvbHVtbnMobF9HX21hdF9sb2N1cykKbF9HX21hdF9tUk5BIDwtIHJlbmFtZV9jb2x1bW5zKGxfR19tYXRfbVJOQSkKbF9HX21hdF9leG9uIDwtIHJlbmFtZV9jb2x1bW5zKGxfR19tYXRfZXhvbikKbF9HX21hdF9DRFMgPC0gcmVuYW1lX2NvbHVtbnMobF9HX21hdF9DRFMpCmxfR19tYXRfaW50cm9uc19maWx0ZXJlZCA8LSByZW5hbWVfY29sdW1ucyhsX0dfbWF0X2ludHJvbnNfZmlsdGVyZWQpCgpsX1FfbWF0X2xvY3VzIDwtIHJlbmFtZV9jb2x1bW5zKGxfUV9tYXRfbG9jdXMpCmxfUV9tYXRfbVJOQSA8LSByZW5hbWVfY29sdW1ucyhsX1FfbWF0X21STkEpCmxfUV9tYXRfZXhvbiA8LSByZW5hbWVfY29sdW1ucyhsX1FfbWF0X2V4b24pCmxfUV9tYXRfQ0RTIDwtIHJlbmFtZV9jb2x1bW5zKGxfUV9tYXRfQ0RTKQpsX1FfbWF0X2ludHJvbnNfZmlsdGVyZWQgPC0gcmVuYW1lX2NvbHVtbnMobF9RX21hdF9pbnRyb25zX2ZpbHRlcmVkKQpgYGAKPC9kZXRhaWxzPgo8YnIgLz4KCiMjIyBDYXRlZ29yaXplIHB1dGF0aXZlIHRyYW5zY3JpcHRzL3RyYW5zY3JpcHQgZnJhZ21lbnRzIGJ5IHBlcmNlbnRpbGUKIyMjIyBDb2RlCjxkZXRhaWxzPgo8c3VtbWFyeT48aT5Db2RlOiBDYXRlZ29yaXplIHB1dGF0aXZlIHRyYW5zY3JpcHRzL3RyYW5zY3JpcHQgZnJhZ21lbnRzIGJ5IHBlcmNlbnRpbGU8L2k+PC9zdW1tYXJ5PgoKYGBge3J9CiMhL3Vzci9iaW4vZW52IFJzY3JpcHQKCiMgIEluaXRpYWxpemUgZnVuY3Rpb24gLS0tLS0tLS0tLS0tLS0tLQpmaWx0ZXJfdHJhbnNmcmFncyA8LSBmdW5jdGlvbih4LCB5KSB7CiAgICBkZiA8LSB4CiAgICAKICAgIGlmKHkgPT0gIkcxIiB8IHkgPT0gIkciKSB7CiAgICAgICAgZGYgPC0geFssIDE6M10gJT4lIGhlYWQoLiwgLTUpCiAgICB9IGVsc2UgaWYoeSA9PSAiUSIpIHsKICAgICAgICBkZiA8LSB4WywgYygxLCA2LCA3KV0gJT4lIGhlYWQoLiwgLTUpCiAgICB9IGVsc2UgaWYoeSAhPSAiRzEiIHwgeSAhPSAiRyIgfCB5ICE9ICJRIikgewogICAgICAgIHN0b3AoIlBhcmFtZXRlciB5IG11c3QgYmUgZWl0aGVyICdHMScsICdHJywgb3IgJ1EnIikKICAgIH0KICAgIAogICAgZGZbLCA0XSA8LSBkZlssIDJdICsgZGZbLCAzXQogICAgY29sbmFtZXMoZGYpWzRdIDwtICJzdW0iCgogICAgaWRzIDwtIGxpc3QoKQoKICAgIGlkcyRwZXJjZW50aWxlcyA8LSBxdWFudGlsZSgKICAgICAgICBkZiRzdW0sCiAgICAgICAgcHJvYnMgPSBjKAogICAgICAgICAgICAwLjA1LCAwLjEwLCAwLjE1LCAwLjIwLCAwLjI1LCAwLjMwLCAwLjM1LCAwLjQwLCAwLjQ1LCAwLjUwLAogICAgICAgICAgICAwLjU1LCAwLjYwLCAwLjY1LCAwLjcwLCAwLjc1LCAwLjgwLCAwLjg1LCAwLjkwLCAwLjk1CiAgICAgICAgKQogICAgKSAlPiUKICAgICAgICByb3VuZCgpCiAgICAKICAgIGRmJGJlbG93XzA1IDwtIGlmZWxzZShkZiRzdW0gPD0gaWRzJHBlcmNlbnRpbGVzWzFdLCBUUlVFLCBGQUxTRSkKICAgIGRmJGJlbG93XzEwIDwtIGlmZWxzZShkZiRzdW0gPD0gaWRzJHBlcmNlbnRpbGVzWzJdLCBUUlVFLCBGQUxTRSkKICAgIGRmJGJlbG93XzE1IDwtIGlmZWxzZShkZiRzdW0gPD0gaWRzJHBlcmNlbnRpbGVzWzNdLCBUUlVFLCBGQUxTRSkKICAgIGRmJGJlbG93XzIwIDwtIGlmZWxzZShkZiRzdW0gPD0gaWRzJHBlcmNlbnRpbGVzWzRdLCBUUlVFLCBGQUxTRSkKICAgIGRmJGJlbG93XzI1IDwtIGlmZWxzZShkZiRzdW0gPD0gaWRzJHBlcmNlbnRpbGVzWzVdLCBUUlVFLCBGQUxTRSkKICAgIGRmJGJlbG93XzMwIDwtIGlmZWxzZShkZiRzdW0gPD0gaWRzJHBlcmNlbnRpbGVzWzZdLCBUUlVFLCBGQUxTRSkKICAgIGRmJGJlbG93XzM1IDwtIGlmZWxzZShkZiRzdW0gPD0gaWRzJHBlcmNlbnRpbGVzWzddLCBUUlVFLCBGQUxTRSkKICAgIGRmJGJlbG93XzQwIDwtIGlmZWxzZShkZiRzdW0gPD0gaWRzJHBlcmNlbnRpbGVzWzhdLCBUUlVFLCBGQUxTRSkKICAgIGRmJGJlbG93XzQ1IDwtIGlmZWxzZShkZiRzdW0gPD0gaWRzJHBlcmNlbnRpbGVzWzldLCBUUlVFLCBGQUxTRSkKICAgIGRmJGJlbG93XzUwIDwtIGlmZWxzZShkZiRzdW0gPD0gaWRzJHBlcmNlbnRpbGVzWzEwXSwgVFJVRSwgRkFMU0UpCiAgICBkZiRiZWxvd181NSA8LSBpZmVsc2UoZGYkc3VtIDw9IGlkcyRwZXJjZW50aWxlc1sxMV0sIFRSVUUsIEZBTFNFKQogICAgZGYkYmVsb3dfNjAgPC0gaWZlbHNlKGRmJHN1bSA8PSBpZHMkcGVyY2VudGlsZXNbMTJdLCBUUlVFLCBGQUxTRSkKICAgIGRmJGJlbG93XzY1IDwtIGlmZWxzZShkZiRzdW0gPD0gaWRzJHBlcmNlbnRpbGVzWzEzXSwgVFJVRSwgRkFMU0UpCiAgICBkZiRiZWxvd183MCA8LSBpZmVsc2UoZGYkc3VtIDw9IGlkcyRwZXJjZW50aWxlc1sxNF0sIFRSVUUsIEZBTFNFKQogICAgZGYkYmVsb3dfNzUgPC0gaWZlbHNlKGRmJHN1bSA8PSBpZHMkcGVyY2VudGlsZXNbMTVdLCBUUlVFLCBGQUxTRSkKICAgIGRmJGJlbG93XzgwIDwtIGlmZWxzZShkZiRzdW0gPD0gaWRzJHBlcmNlbnRpbGVzWzE2XSwgVFJVRSwgRkFMU0UpCiAgICBkZiRiZWxvd184NSA8LSBpZmVsc2UoZGYkc3VtIDw9IGlkcyRwZXJjZW50aWxlc1sxN10sIFRSVUUsIEZBTFNFKQogICAgZGYkYmVsb3dfOTAgPC0gaWZlbHNlKGRmJHN1bSA8PSBpZHMkcGVyY2VudGlsZXNbMThdLCBUUlVFLCBGQUxTRSkKICAgIGRmJGJlbG93Xzk1IDwtIGlmZWxzZShkZiRzdW0gPD0gaWRzJHBlcmNlbnRpbGVzWzE5XSwgVFJVRSwgRkFMU0UpCiAgICAKICAgIGlkcyRiZWxvd18wNSA8LSBkZltkZiRiZWxvd18wNSA9PSBGQUxTRSwgXSRpZAogICAgaWRzJGJlbG93XzEwIDwtIGRmW2RmJGJlbG93XzEwID09IEZBTFNFLCBdJGlkCiAgICBpZHMkYmVsb3dfMTUgPC0gZGZbZGYkYmVsb3dfMTUgPT0gRkFMU0UsIF0kaWQKICAgIGlkcyRiZWxvd18yMCA8LSBkZltkZiRiZWxvd18yMCA9PSBGQUxTRSwgXSRpZAogICAgaWRzJGJlbG93XzI1IDwtIGRmW2RmJGJlbG93XzI1ID09IEZBTFNFLCBdJGlkCiAgICBpZHMkYmVsb3dfMzAgPC0gZGZbZGYkYmVsb3dfMzAgPT0gRkFMU0UsIF0kaWQKICAgIGlkcyRiZWxvd18zNSA8LSBkZltkZiRiZWxvd18zNSA9PSBGQUxTRSwgXSRpZAogICAgaWRzJGJlbG93XzQwIDwtIGRmW2RmJGJlbG93XzQwID09IEZBTFNFLCBdJGlkCiAgICBpZHMkYmVsb3dfNDUgPC0gZGZbZGYkYmVsb3dfNDUgPT0gRkFMU0UsIF0kaWQKICAgIGlkcyRiZWxvd181MCA8LSBkZltkZiRiZWxvd181MCA9PSBGQUxTRSwgXSRpZAogICAgaWRzJGJlbG93XzU1IDwtIGRmW2RmJGJlbG93XzU1ID09IEZBTFNFLCBdJGlkCiAgICBpZHMkYmVsb3dfNjAgPC0gZGZbZGYkYmVsb3dfNjAgPT0gRkFMU0UsIF0kaWQKICAgIGlkcyRiZWxvd182NSA8LSBkZltkZiRiZWxvd182NSA9PSBGQUxTRSwgXSRpZAogICAgaWRzJGJlbG93XzcwIDwtIGRmW2RmJGJlbG93XzcwID09IEZBTFNFLCBdJGlkCiAgICBpZHMkYmVsb3dfNzUgPC0gZGZbZGYkYmVsb3dfNzUgPT0gRkFMU0UsIF0kaWQKICAgIGlkcyRiZWxvd184MCA8LSBkZltkZiRiZWxvd184MCA9PSBGQUxTRSwgXSRpZAogICAgaWRzJGJlbG93Xzg1IDwtIGRmW2RmJGJlbG93Xzg1ID09IEZBTFNFLCBdJGlkCiAgICBpZHMkYmVsb3dfOTAgPC0gZGZbZGYkYmVsb3dfOTAgPT0gRkFMU0UsIF0kaWQKICAgIGlkcyRiZWxvd185NSA8LSBkZltkZiRiZWxvd185NSA9PSBGQUxTRSwgXSRpZAogICAgCiAgICByZXR1cm4oaWRzKQp9CgoKIyAgRzEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmZfR19tYXRfbG9jdXMgPC0gc2FwcGx5KAogICAgbF9HX21hdF9sb2N1cywKICAgIGZpbHRlcl90cmFuc2ZyYWdzLAogICAgc2ltcGxpZnkgPSBGQUxTRSwKICAgIFVTRS5OQU1FUyA9IFRSVUUsCiAgICB5ID0gIkcxIgopCmZfR19tYXRfbVJOQSA8LSBzYXBwbHkoCiAgICBsX0dfbWF0X21STkEsCiAgICBmaWx0ZXJfdHJhbnNmcmFncywKICAgIHNpbXBsaWZ5ID0gRkFMU0UsCiAgICBVU0UuTkFNRVMgPSBUUlVFLAogICAgeSA9ICJHMSIKKQpmX0dfbWF0X2V4b24gPC0gc2FwcGx5KAogICAgbF9HX21hdF9leG9uLAogICAgZmlsdGVyX3RyYW5zZnJhZ3MsCiAgICBzaW1wbGlmeSA9IEZBTFNFLAogICAgVVNFLk5BTUVTID0gVFJVRSwKICAgIHkgPSAiRzEiCikKZl9HX21hdF9DRFMgPC0gc2FwcGx5KAogICAgbF9HX21hdF9DRFMsCiAgICBmaWx0ZXJfdHJhbnNmcmFncywKICAgIHNpbXBsaWZ5ID0gRkFMU0UsCiAgICBVU0UuTkFNRVMgPSBUUlVFLAogICAgeSA9ICJHMSIKKQpmX0dfbWF0X2ludHJvbnNfZmlsdGVyZWQgPC0gc2FwcGx5KAogICAgbF9HX21hdF9pbnRyb25zX2ZpbHRlcmVkLAogICAgZmlsdGVyX3RyYW5zZnJhZ3MsCiAgICBzaW1wbGlmeSA9IEZBTFNFLAogICAgVVNFLk5BTUVTID0gVFJVRSwKICAgIHkgPSAiRzEiCikKCiMgIFEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpmX1FfbWF0X2xvY3VzIDwtIHNhcHBseSgKICAgIGxfUV9tYXRfbG9jdXMsCiAgICBmaWx0ZXJfdHJhbnNmcmFncywKICAgIHNpbXBsaWZ5ID0gRkFMU0UsCiAgICBVU0UuTkFNRVMgPSBUUlVFLAogICAgeSA9ICJRIgopCmZfUV9tYXRfbVJOQSA8LSBzYXBwbHkoCiAgICBsX1FfbWF0X21STkEsCiAgICBmaWx0ZXJfdHJhbnNmcmFncywKICAgIHNpbXBsaWZ5ID0gRkFMU0UsCiAgICBVU0UuTkFNRVMgPSBUUlVFLAogICAgeSA9ICJRIgopCmZfUV9tYXRfZXhvbiA8LSBzYXBwbHkoCiAgICBsX1FfbWF0X2V4b24sCiAgICBmaWx0ZXJfdHJhbnNmcmFncywKICAgIHNpbXBsaWZ5ID0gRkFMU0UsCiAgICBVU0UuTkFNRVMgPSBUUlVFLAogICAgeSA9ICJRIgopCmZfUV9tYXRfQ0RTIDwtIHNhcHBseSgKICAgIGxfUV9tYXRfQ0RTLAogICAgZmlsdGVyX3RyYW5zZnJhZ3MsCiAgICBzaW1wbGlmeSA9IEZBTFNFLAogICAgVVNFLk5BTUVTID0gVFJVRSwKICAgIHkgPSAiUSIKKQpmX1FfbWF0X2ludHJvbnNfZmlsdGVyZWQgPC0gc2FwcGx5KAogICAgbF9RX21hdF9pbnRyb25zX2ZpbHRlcmVkLAogICAgZmlsdGVyX3RyYW5zZnJhZ3MsCiAgICBzaW1wbGlmeSA9IEZBTFNFLAogICAgVVNFLk5BTUVTID0gVFJVRSwKICAgIHkgPSAiUSIKKQpgYGAKPC9kZXRhaWxzPgo8YnIgLz4KCiMjIyBTdWJzZXQgYGd0ZmAgYGRhdGEuZnJhbWVgIHRvIHJldGFpbiBwZXJjZW50aWxlLWZpbHRlcmVkIGBnZW5lX2lkYHMKIyMjIyBDb2RlCjxkZXRhaWxzPgo8c3VtbWFyeT48aT5Db2RlOiBTdWJzZXQgYGd0ZmAgYGRhdGEuZnJhbWVgIHRvIHJldGFpbiBwZXJjZW50aWxlLWZpbHRlcmVkIGBnZW5lX2lkYHM8L2k+PC9zdW1tYXJ5PgoKYGBge3J9CiMhL3Vzci9iaW4vZW52IFJzY3JpcHQKCiMgIEluaXRpYWxpemUgZnVuY3Rpb25zIC0tLS0tLS0tLS0tLS0tLQpmbGF0dGVuX2VsZW1lbnRzX3RvX29uZSA8LSBmdW5jdGlvbih4KSB7CiAgICAjIEZvciBjaGFyYWN0ZXIgbGlzdCBlbGVtZW50cyB3aXRoIHR3byBvciBtb3JlIHN1YmVsZW1lbnRzLCBjb2xsYXBzZQogICAgIyAoImZsYXR0ZW4iKSB0aGUgc3ViZWxlbWVudHMgaW50byBhIHNpbmdsZSBjaGFyYWN0ZXIgZWxlbWVudAogICAgIyAKICAgICMgOnBhcmFtIHg6IDxsaXN0PgogICAgIyA6cmV0dXJuOiBjaGFyYWN0ZXIgdmVjdG9yIG9mIGNvbGxhcHNlZCBsaXN0IGVsZW1lbnRzIChsaXN0IGUpCiAgICBsX2NvbGxhcHNlZCA8LSB4W2xlbmd0aHMoeCkgPj0gMl0gJT4lIGxlbmd0aCgpCiAgICBjb2xsYXBzZWQgPC0gdmVjdG9yKG1vZGUgPSAiY2hhcmFjdGVyIiwgbGVuZ3RoID0gbF9jb2xsYXBzZWQpCiAgICBmb3IoaSBpbiAxOmxfY29sbGFwc2VkKSB7CiAgICAgICAgIyBpIDwtIDEKICAgICAgICAjIGNhdChpLCAiXG4iKQogICAgICAgICMgY2F0KHhbbGVuZ3Rocyh4KSA+PSAyXVtbaV1dLCAiXG4iKQogICAgICAgIGNvbGxhcHNlZFtpXSA8LSBzdHJpbmdyOjpzdHJfYygKICAgICAgICAgICAgeFtsZW5ndGhzKHgpID49IDJdW1tpXV0sCiAgICAgICAgICAgIGNvbGxhcHNlID0gIiwgIgogICAgICAgICkKICAgIH0KICAgIAogICAgcmV0dXJuKGNvbGxhcHNlZCkKfQoKCnByb2Nlc3NfbGlzdF9jb2x1bW4gPC0gZnVuY3Rpb24oeCkgewogICAgIyAuLi4KICAgICMgCiAgICAjIDpwYXJhbSB4OiA8bGlzdD4KICAgICMgOnJldHVybjogLi4uCiAgICB4W2xlbmd0aHMoeCkgPT0gMF0gPC0gTkFfY2hhcmFjdGVyXwogICAgaWYobGVuZ3RoKHhbbGVuZ3Rocyh4KSA+PSAyXSkgIT0gMCkgewogICAgICAgIHhbbGVuZ3Rocyh4KSA+PSAyXSA8LSB4W2xlbmd0aHMoeCkgPj0gMl0gJT4lCiAgICAgICAgICAgIGZsYXR0ZW5fZWxlbWVudHNfdG9fb25lKCkKICAgIH0KICAgIHkgPC0geCAlPiUgdW5saXN0KCkKICAgIHJldHVybih5KQp9CgoKc3Vic2V0X2RhdGFmcmFtZXMgPC0gZnVuY3Rpb24oeCwgeSwgeikgewogICAgIyAuLi4KICAgICMgCiAgICAjIDpwYXJhbSB4OiBsaXN0IG9mICouZ2ZmMyBmaWxlcyA8bGlzdD4KICAgICMgOnBhcmFtIHk6IGxpc3Qgb2YgcHV0YXRpdmUgdHJhbnNjcmlwdHMgY2F0ZWdvcml6ZWQgYnkgcGVyY2VudGlsZSA8bGlzdD4KICAgICMgOnBhcmFtIHo6IGZlYXR1cmUgdHlwZSB0byBleGFtaW5lOyBtdXN0IGJlICJsb2N1cyIsICJtUk5BIiwgImV4b24iLCAiQ0RTIiwgb3IgImdlbmUiIDxjaHI+CiAgICAKICAgICMgIFRlc3RzCiAgICAjIHggPC0gbF9RX2d0ZgogICAgIyB5IDwtIGZfUV9tYXRfQ0RTCiAgICAjIHogPC0gIkNEUyIKICAgICMgCiAgICAjIHggPC0gbF9HX2d0Zl9pbnRyb25zX2ZpbHRlcmVkCiAgICAjIHkgPC0gZl9HX21hdF9pbnRyb25zX2ZpbHRlcmVkCiAgICAjIHogPC0gImdlbmUiCiAgICAjIAogICAgIyB4IDwtIGxfUV9ndGYKICAgICMgeSA8LSBmX1FfbWF0X2V4b24KICAgICMgeiA8LSAiZXhvbiIKICAgIAogICAgaWYoKGJhc2U6OmlzRkFMU0Uoc3RyaW5ncjo6c3RyX2RldGVjdCh6LCAibG9jdXN8bVJOQXxleG9ufENEU3xnZW5lIikpKSkgewogICAgICAgIHN0b3AoInogbXVzdCBiZSBcImxvY3VzXCIsIFwibVJOQVwiLCBcImV4b25cIiwgXCJDRFNcIiwgb3IgXCJnZW5lXCIiKQogICAgfQogICAgCiAgICBkZiA8LSBsaXN0KCkKICAgIG1hdCA8LSBsaXN0KCkKICAgIG91dCA8LSBsaXN0KCkKICAgIAogICAgZm9yKGkgaW4gbmFtZXMoeCkpIHsKICAgICAgICAjICBUZXN0cwogICAgICAgICMgaSA8LSAiazEiCiAgICAgICAgIyBpIDwtICJrNCIKICAgICAgICAKICAgICAgICBtYXRbW2ldXSA8LSB5W1tpXV0KICAgICAgICAKICAgICAgICBpZihiYXNlOjppc1RSVUUoeiA9PSAibG9jdXMiKSkgewogICAgICAgICAgICBkZltbaV1dIDwtIHhbW2ldXVt4W1tpXV1bInR5cGUiXSA9PSAibG9jdXMiLCBdCiAgICAgICAgfSBlbHNlIGlmKGJhc2U6OmlzVFJVRSh6ID09ICJtUk5BIikpIHsKICAgICAgICAgICAgZGZbW2ldXSA8LSB4W1tpXV1beFtbaV1dWyJ0eXBlIl0gPT0gIm1STkEiLCBdCiAgICAgICAgfSBlbHNlIGlmKGJhc2U6OmlzVFJVRSh6ID09ICJleG9uIikpIHsKICAgICAgICAgICAgZGZbW2ldXSA8LSB4W1tpXV1beFtbaV1dWyJ0eXBlIl0gPT0gImV4b24iLCBdCiAgICAgICAgfSBlbHNlIGlmKGJhc2U6OmlzVFJVRSh6ID09ICJDRFMiKSkgewogICAgICAgICAgICBkZltbaV1dIDwtIHhbW2ldXVt4W1tpXV1bInR5cGUiXSA9PSAiQ0RTIiwgXQogICAgICAgIH0gZWxzZSBpZihiYXNlOjppc1RSVUUoeiA9PSAiZ2VuZSIpKSB7CiAgICAgICAgICAgIGRmW1tpXV0gPC0geFtbaV1dW3hbW2ldXVsidHlwZSJdID09ICJnZW5lIiwgXQogICAgICAgIH0gCiAgICAgICAgCiAgICAgICAgaWYoYmFzZTo6aXNUUlVFKHN0cmluZ3I6OnN0cl9kZXRlY3QoeiwgImxvY3VzfG1STkF8Z2VuZSIpKSkgewogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd18wNSA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd18wNSwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd18xMCA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd18xMCwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd18xNSA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd18xNSwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd18yMCA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd18yMCwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd18yNSA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd18yNSwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd18zMCA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd18zMCwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd18zNSA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd18zNSwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd180MCA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd180MCwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd180NSA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd180NSwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd181MCA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd181MCwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd181NSA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd181NSwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd182MCA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd182MCwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd182NSA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd182NSwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd183MCA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd183MCwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd183NSA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd183NSwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd184MCA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd184MCwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd184NSA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd184NSwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd185MCA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd185MCwgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd185NSA8LSBkZltbaV1dW2RmW1tpXV0kSUQgJWluJSBtYXRbW2ldXSRiZWxvd185NSwgXQogICAgICAgIH0gZWxzZSBpZihiYXNlOjppc1RSVUUoc3RyaW5ncjo6c3RyX2RldGVjdCh6LCAiZXhvbnxDRFMiKSkpIHsKICAgICAgICAgICAgb3V0W1tpXV0kYmVsb3dfMDUgPC0gZGZbW2ldXVsKICAgICAgICAgICAgICAgIHByb2Nlc3NfbGlzdF9jb2x1bW4oZGZbW2ldXSRQYXJlbnQpICVpbiUgbWF0W1tpXV0kYmVsb3dfMDUsIAogICAgICAgICAgICBdCiAgICAgICAgICAgIG91dFtbaV1dJGJlbG93XzEwIDwtIGRmW1tpXV1bCiAgICAgICAgICAgICAgICBwcm9jZXNzX2xpc3RfY29sdW1uKGRmW1tpXV0kUGFyZW50KSAlaW4lIG1hdFtbaV1dJGJlbG93XzEwLCAKICAgICAgICAgICAgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd18xNSA8LSBkZltbaV1dWwogICAgICAgICAgICAgICAgcHJvY2Vzc19saXN0X2NvbHVtbihkZltbaV1dJFBhcmVudCkgJWluJSBtYXRbW2ldXSRiZWxvd18xNSwgCiAgICAgICAgICAgIF0KICAgICAgICAgICAgb3V0W1tpXV0kYmVsb3dfMjAgPC0gZGZbW2ldXVsKICAgICAgICAgICAgICAgIHByb2Nlc3NfbGlzdF9jb2x1bW4oZGZbW2ldXSRQYXJlbnQpICVpbiUgbWF0W1tpXV0kYmVsb3dfMjAsIAogICAgICAgICAgICBdCiAgICAgICAgICAgIG91dFtbaV1dJGJlbG93XzI1IDwtIGRmW1tpXV1bCiAgICAgICAgICAgICAgICBwcm9jZXNzX2xpc3RfY29sdW1uKGRmW1tpXV0kUGFyZW50KSAlaW4lIG1hdFtbaV1dJGJlbG93XzI1LCAKICAgICAgICAgICAgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd18zMCA8LSBkZltbaV1dWwogICAgICAgICAgICAgICAgcHJvY2Vzc19saXN0X2NvbHVtbihkZltbaV1dJFBhcmVudCkgJWluJSBtYXRbW2ldXSRiZWxvd18zMCwgCiAgICAgICAgICAgIF0KICAgICAgICAgICAgb3V0W1tpXV0kYmVsb3dfMzUgPC0gZGZbW2ldXVsKICAgICAgICAgICAgICAgIHByb2Nlc3NfbGlzdF9jb2x1bW4oZGZbW2ldXSRQYXJlbnQpICVpbiUgbWF0W1tpXV0kYmVsb3dfMzUsIAogICAgICAgICAgICBdCiAgICAgICAgICAgIG91dFtbaV1dJGJlbG93XzQwIDwtIGRmW1tpXV1bCiAgICAgICAgICAgICAgICBwcm9jZXNzX2xpc3RfY29sdW1uKGRmW1tpXV0kUGFyZW50KSAlaW4lIG1hdFtbaV1dJGJlbG93XzQwLCAKICAgICAgICAgICAgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd180NSA8LSBkZltbaV1dWwogICAgICAgICAgICAgICAgcHJvY2Vzc19saXN0X2NvbHVtbihkZltbaV1dJFBhcmVudCkgJWluJSBtYXRbW2ldXSRiZWxvd180NSwgCiAgICAgICAgICAgIF0KICAgICAgICAgICAgb3V0W1tpXV0kYmVsb3dfNTAgPC0gZGZbW2ldXVsKICAgICAgICAgICAgICAgIHByb2Nlc3NfbGlzdF9jb2x1bW4oZGZbW2ldXSRQYXJlbnQpICVpbiUgbWF0W1tpXV0kYmVsb3dfNTAsIAogICAgICAgICAgICBdCiAgICAgICAgICAgIG91dFtbaV1dJGJlbG93XzU1IDwtIGRmW1tpXV1bCiAgICAgICAgICAgICAgICBwcm9jZXNzX2xpc3RfY29sdW1uKGRmW1tpXV0kUGFyZW50KSAlaW4lIG1hdFtbaV1dJGJlbG93XzU1LCAKICAgICAgICAgICAgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd182MCA8LSBkZltbaV1dWwogICAgICAgICAgICAgICAgcHJvY2Vzc19saXN0X2NvbHVtbihkZltbaV1dJFBhcmVudCkgJWluJSBtYXRbW2ldXSRiZWxvd182MCwgCiAgICAgICAgICAgIF0KICAgICAgICAgICAgb3V0W1tpXV0kYmVsb3dfNjUgPC0gZGZbW2ldXVsKICAgICAgICAgICAgICAgIHByb2Nlc3NfbGlzdF9jb2x1bW4oZGZbW2ldXSRQYXJlbnQpICVpbiUgbWF0W1tpXV0kYmVsb3dfNjUsIAogICAgICAgICAgICBdCiAgICAgICAgICAgIG91dFtbaV1dJGJlbG93XzcwIDwtIGRmW1tpXV1bCiAgICAgICAgICAgICAgICBwcm9jZXNzX2xpc3RfY29sdW1uKGRmW1tpXV0kUGFyZW50KSAlaW4lIG1hdFtbaV1dJGJlbG93XzcwLCAKICAgICAgICAgICAgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd183NSA8LSBkZltbaV1dWwogICAgICAgICAgICAgICAgcHJvY2Vzc19saXN0X2NvbHVtbihkZltbaV1dJFBhcmVudCkgJWluJSBtYXRbW2ldXSRiZWxvd183NSwgCiAgICAgICAgICAgIF0KICAgICAgICAgICAgb3V0W1tpXV0kYmVsb3dfODAgPC0gZGZbW2ldXVsKICAgICAgICAgICAgICAgIHByb2Nlc3NfbGlzdF9jb2x1bW4oZGZbW2ldXSRQYXJlbnQpICVpbiUgbWF0W1tpXV0kYmVsb3dfODAsIAogICAgICAgICAgICBdCiAgICAgICAgICAgIG91dFtbaV1dJGJlbG93Xzg1IDwtIGRmW1tpXV1bCiAgICAgICAgICAgICAgICBwcm9jZXNzX2xpc3RfY29sdW1uKGRmW1tpXV0kUGFyZW50KSAlaW4lIG1hdFtbaV1dJGJlbG93Xzg1LCAKICAgICAgICAgICAgXQogICAgICAgICAgICBvdXRbW2ldXSRiZWxvd185MCA8LSBkZltbaV1dWwogICAgICAgICAgICAgICAgcHJvY2Vzc19saXN0X2NvbHVtbihkZltbaV1dJFBhcmVudCkgJWluJSBtYXRbW2ldXSRiZWxvd185MCwgCiAgICAgICAgICAgIF0KICAgICAgICAgICAgb3V0W1tpXV0kYmVsb3dfOTUgPC0gZGZbW2ldXVsKICAgICAgICAgICAgICAgIHByb2Nlc3NfbGlzdF9jb2x1bW4oZGZbW2ldXSRQYXJlbnQpICVpbiUgbWF0W1tpXV0kYmVsb3dfOTUsIAogICAgICAgICAgICBdCiAgICAgICAgfQogICAgfQogICAgCiAgICByZXR1cm4ob3V0KQp9CgoKIyAgRzEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCm91dF9HX2d0Zl9sb2N1cyA8LSBzdWJzZXRfZGF0YWZyYW1lcyhsX0dfZ3RmLCBmX0dfbWF0X2xvY3VzLCAibG9jdXMiKQpvdXRfR19ndGZfbVJOQSA8LSBzdWJzZXRfZGF0YWZyYW1lcyhsX0dfZ3RmLCBmX0dfbWF0X21STkEsICJtUk5BIikKb3V0X0dfZ3RmX2V4b24gPC0gc3Vic2V0X2RhdGFmcmFtZXMobF9HX2d0ZiwgZl9HX21hdF9leG9uLCAiZXhvbiIpCm91dF9HX2d0Zl9DRFMgPC0gc3Vic2V0X2RhdGFmcmFtZXMobF9HX2d0ZiwgZl9HX21hdF9DRFMsICJDRFMiKQpvdXRfR19ndGZfaW50cm9uc19maWx0ZXJlZCA8LSBzdWJzZXRfZGF0YWZyYW1lcygKICAgIGxfR19ndGZfaW50cm9uc19maWx0ZXJlZCwgZl9HX21hdF9pbnRyb25zX2ZpbHRlcmVkLCAiZ2VuZSIKKQoKCiMgIFEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpvdXRfUV9ndGZfbG9jdXMgPC0gc3Vic2V0X2RhdGFmcmFtZXMobF9RX2d0ZiwgZl9RX21hdF9sb2N1cywgImxvY3VzIikKb3V0X1FfZ3RmX21STkEgPC0gc3Vic2V0X2RhdGFmcmFtZXMobF9RX2d0ZiwgZl9RX21hdF9tUk5BLCAibVJOQSIpCm91dF9RX2d0Zl9leG9uIDwtIHN1YnNldF9kYXRhZnJhbWVzKGxfUV9ndGYsIGZfUV9tYXRfZXhvbiwgImV4b24iKQpvdXRfUV9ndGZfQ0RTIDwtIHN1YnNldF9kYXRhZnJhbWVzKGxfUV9ndGYsIGZfUV9tYXRfQ0RTLCAiQ0RTIikKb3V0X1FfZ3RmX2ludHJvbnNfZmlsdGVyZWQgPC0gc3Vic2V0X2RhdGFmcmFtZXMoCiAgICBsX1FfZ3RmX2ludHJvbnNfZmlsdGVyZWQsIGZfUV9tYXRfaW50cm9uc19maWx0ZXJlZCwgImdlbmUiCikKYGBgCjwvZGV0YWlscz4KPGJyIC8+CgojIyMgV3JpdGUgb3V0IHByb2Nlc3NlZCBgZ3RmYHMKIyMjIyBDb2RlCjxkZXRhaWxzPgo8c3VtbWFyeT48aT5Db2RlOiBXcml0ZSBvdXQgcHJvY2Vzc2VkIGBndGZgczwvaT48L3N1bW1hcnk+CgpgYGB7cn0KIyEvdXNyL2Jpbi9lbnYgUnNjcmlwdAoKIyAgSW5pdGlhbGl6ZSBmdW5jdGlvbnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQp3cml0ZV9ndGYgPC0gZnVuY3Rpb24oeCwgeSkgewogICAgIyAuLi4KICAgICMgCiAgICAjIDpwYXJhbSB4OiB0aWJibGUgPHRpYmJsZSwgZGF0YS5mcmFtZT4KICAgICMgOnBhcmFtIHk6IG91dGZpbGUgPGNocj4KICAgICMgOnJldHVybjogTkEKICAgIHJlYWRyOjp3cml0ZV90c3YoCiAgICAgICAgeCwKICAgICAgICB5LAogICAgICAgIGNvbF9uYW1lcyA9IEZBTFNFLAogICAgICAgIHF1b3RlID0gIm5vbmUiLAogICAgICAgIGVzY2FwZSA9ICJub25lIgogICAgKQp9CgoKIyAgQ3JlYXRlIG91dGRpcmVjdG9yaWVzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojICBHMSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KcGF0aF9HX2xvY3VzIDwtICJvdXRmaWxlc19ndGYtZ2ZmMy9UcmluaXR5LUdHL0dfTi9maWx0ZXJlZC9sb2N1cyIKaWYoYmFzZTo6aXNGQUxTRShkaXIuZXhpc3RzKHBhdGhfR19sb2N1cykpKSBkaXIuY3JlYXRlKHBhdGhfR19sb2N1cywgcmVjdXJzaXZlID0gVFJVRSkKCnBhdGhfR19tUk5BIDwtICJvdXRmaWxlc19ndGYtZ2ZmMy9UcmluaXR5LUdHL0dfTi9maWx0ZXJlZC9tUk5BIgppZihiYXNlOjppc0ZBTFNFKGRpci5leGlzdHMocGF0aF9HX21STkEpKSkgZGlyLmNyZWF0ZShwYXRoX0dfbVJOQSwgcmVjdXJzaXZlID0gVFJVRSkKCnBhdGhfR19leG9uIDwtICJvdXRmaWxlc19ndGYtZ2ZmMy9UcmluaXR5LUdHL0dfTi9maWx0ZXJlZC9leG9uIgppZihiYXNlOjppc0ZBTFNFKGRpci5leGlzdHMocGF0aF9HX2V4b24pKSkgZGlyLmNyZWF0ZShwYXRoX0dfZXhvbiwgcmVjdXJzaXZlID0gVFJVRSkKCnBhdGhfR19DRFMgPC0gIm91dGZpbGVzX2d0Zi1nZmYzL1RyaW5pdHktR0cvR19OL2ZpbHRlcmVkL0NEUyIKaWYoYmFzZTo6aXNGQUxTRShkaXIuZXhpc3RzKHBhdGhfR19DRFMpKSkgZGlyLmNyZWF0ZShwYXRoX0dfQ0RTLCByZWN1cnNpdmUgPSBUUlVFKQoKcGF0aF9HX2ludHJvbnNfZmlsdGVyZWQgPC0gIm91dGZpbGVzX2d0Zi1nZmYzL1RyaW5pdHktR0cvR19OL2ZpbHRlcmVkL2ludHJvbnNfZmlsdGVyZWQiCmlmKGJhc2U6OmlzRkFMU0UoZGlyLmV4aXN0cyhwYXRoX0dfaW50cm9uc19maWx0ZXJlZCkpKSBkaXIuY3JlYXRlKHBhdGhfR19pbnRyb25zX2ZpbHRlcmVkLCByZWN1cnNpdmUgPSBUUlVFKQoKIyAgUSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnBhdGhfUV9sb2N1cyA8LSAib3V0ZmlsZXNfZ3RmLWdmZjMvVHJpbml0eS1HRy9RX04vZmlsdGVyZWQvbG9jdXMiCmlmKGJhc2U6OmlzRkFMU0UoZGlyLmV4aXN0cyhwYXRoX1FfbG9jdXMpKSkgZGlyLmNyZWF0ZShwYXRoX1FfbG9jdXMsIHJlY3Vyc2l2ZSA9IFRSVUUpCgpwYXRoX1FfbVJOQSA8LSAib3V0ZmlsZXNfZ3RmLWdmZjMvVHJpbml0eS1HRy9RX04vZmlsdGVyZWQvbVJOQSIKaWYoYmFzZTo6aXNGQUxTRShkaXIuZXhpc3RzKHBhdGhfUV9tUk5BKSkpIGRpci5jcmVhdGUocGF0aF9RX21STkEsIHJlY3Vyc2l2ZSA9IFRSVUUpCgpwYXRoX1FfZXhvbiA8LSAib3V0ZmlsZXNfZ3RmLWdmZjMvVHJpbml0eS1HRy9RX04vZmlsdGVyZWQvZXhvbiIKaWYoYmFzZTo6aXNGQUxTRShkaXIuZXhpc3RzKHBhdGhfUV9leG9uKSkpIGRpci5jcmVhdGUocGF0aF9RX2V4b24sIHJlY3Vyc2l2ZSA9IFRSVUUpCgpwYXRoX1FfQ0RTIDwtICJvdXRmaWxlc19ndGYtZ2ZmMy9UcmluaXR5LUdHL1FfTi9maWx0ZXJlZC9DRFMiCmlmKGJhc2U6OmlzRkFMU0UoZGlyLmV4aXN0cyhwYXRoX1FfQ0RTKSkpIGRpci5jcmVhdGUocGF0aF9RX0NEUywgcmVjdXJzaXZlID0gVFJVRSkKCnBhdGhfUV9pbnRyb25zX2ZpbHRlcmVkIDwtICJvdXRmaWxlc19ndGYtZ2ZmMy9UcmluaXR5LUdHL1FfTi9maWx0ZXJlZC9pbnRyb25zX2ZpbHRlcmVkIgppZihiYXNlOjppc0ZBTFNFKGRpci5leGlzdHMocGF0aF9RX2ludHJvbnNfZmlsdGVyZWQpKSkgZGlyLmNyZWF0ZShwYXRoX1FfaW50cm9uc19maWx0ZXJlZCwgcmVjdXJzaXZlID0gVFJVRSkKCgojICBDcmVhdGUgb3V0ZGlyZWN0b3JpZXMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmZvcihpIGluIG5hbWVzKG91dF9HX2d0Zl9sb2N1cykpIHsKICAgIGZvcihqIGluIGMocGFzdGUwKAogICAgICAgICJiZWxvd18iLAogICAgICAgIGMoCiAgICAgICAgICAgICIwNSIsICIxMCIsICIxNSIsICIyMCIsICIyNSIsICIzMCIsICIzNSIsICI0MCIsICI0NSIsICI1MCIsCiAgICAgICAgICAgICI1NSIsICI2MCIsICI2NSIsICI3MCIsICI3NSIsICI4MCIsICI4NSIsICI5MCIsICI5NSIKICAgICAgICApCiAgICApKSkgewogICAgICAgIGZvcihrIGluIGMoCiAgICAgICAgICAgIHBhdGhfR19sb2N1cywgcGF0aF9HX21STkEsIHBhdGhfR19leG9uLCBwYXRoX0dfQ0RTLAogICAgICAgICAgICBwYXRoX0dfaW50cm9uc19maWx0ZXJlZCwKICAgICAgICAgICAgcGF0aF9RX2xvY3VzLCBwYXRoX1FfbVJOQSwgcGF0aF9RX2V4b24sIHBhdGhfUV9DRFMsCiAgICAgICAgICAgIHBhdGhfUV9pbnRyb25zX2ZpbHRlcmVkCiAgICAgICAgKSkgewogICAgICAgICAgICAjIGkgPC0gImsyIgogICAgICAgICAgICAjIGogPC0gImJlbG93XzA1IgogICAgICAgICAgICAjIGsgPC0gcGF0aF9RX2xvY3VzCiAgICAgICAgICAgIGlmKGJhc2U6OmlzVFJVRShrID09IHBhdGhfR19sb2N1cykpIHsKICAgICAgICAgICAgICAgICNQSUNLVVBIRVJFCiAgICAgICAgICAgICAgICBvdXRmaWxlIDwtIHBhc3RlMCgKICAgICAgICAgICAgICAgICAgICBwYXRoX0dfbG9jdXMsICIvRzFfbWtjLSIsIGdzdWIoImsiLCAiIiwgaSksICJfIiwKICAgICAgICAgICAgICAgICAgICBnc3ViKCJiZWxvd18iLCAiZ3RlLXBjdGwtIiwgaiksICIuZ3RmIgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICBjYXQoIlNhdmluZyBHMSIsIGksIGosICJpbiIsIGssICJcbiIpCiAgICAgICAgICAgICAgICBjYXQocGFzdGUwKG91dGZpbGUsICJcbiIpKQogICAgICAgICAgICAgICAgY2F0KCJcblxuIikKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgIyBvdXRfR19jb252IDwtIEdlbm9taWNSYW5nZXM6Om1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZSgKICAgICAgICAgICAgICAgICMgICAgIG91dF9HX2d0Zl9sb2N1c1tbaV1dW1tqXV0sIGtlZXAuZXh0cmEuY29sdW1ucyA9IFRSVUUKICAgICAgICAgICAgICAgICMgKQogICAgICAgICAgICAgICAgIyAKICAgICAgICAgICAgICAgICMgcnRyYWNrbGF5ZXI6OmV4cG9ydCgKICAgICAgICAgICAgICAgICMgICAgIG91dF9HX2d0Zl9sb2N1c1tbaV1dW1tqXV0sCiAgICAgICAgICAgICAgICAjICAgICBwYXN0ZTAoCiAgICAgICAgICAgICAgICAjICAgICAgICAgcGF0aF9HX2xvY3VzLCAiL0cxX21rYy0iLCBnc3ViKCJrIiwgIiIsIGkpLCAiXyIsCiAgICAgICAgICAgICAgICAjICAgICAgICAgZ3N1YigiYmVsb3dfIiwgImd0ZS1wY3RsLSIsIGopLCAiLmd0ZiIKICAgICAgICAgICAgICAgICMgICAgICkKICAgICAgICAgICAgICAgICMgKQogICAgICAgICAgICB9IGVsc2UgaWYoYmFzZTo6aXNUUlVFKGsgPT0gcGF0aF9HX21STkEpKSB7CiAgICAgICAgICAgICAgICBvdXRmaWxlIDwtIHBhc3RlMCgKICAgICAgICAgICAgICAgICAgICBwYXRoX0dfbVJOQSwgIi9HMV9ta2MtIiwgZ3N1YigiayIsICIiLCBpKSwgIl8iLAogICAgICAgICAgICAgICAgICAgIGdzdWIoImJlbG93XyIsICJndGUtcGN0bC0iLCBqKSwgIi5ndGYiCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIGNhdCgiU2F2aW5nIEcxIiwgaSwgaiwgImluIiwgaywgIlxuIikKICAgICAgICAgICAgICAgIGNhdChwYXN0ZTAob3V0ZmlsZSwgIlxuIikpCiAgICAgICAgICAgICAgICBjYXQoIlxuXG4iKQogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAjIG91dF9HX2NvbnYgPC0gR2Vub21pY1Jhbmdlczo6bWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKAogICAgICAgICAgICAgICAgIyAgICAgb3V0X0dfZ3RmX21STkFbW2ldXVtbal1dLCBrZWVwLmV4dHJhLmNvbHVtbnMgPSBUUlVFCiAgICAgICAgICAgICAgICAjICkKICAgICAgICAgICAgICAgICMgCiAgICAgICAgICAgICAgICAjIHJ0cmFja2xheWVyOjpleHBvcnQoCiAgICAgICAgICAgICAgICAjICAgICBvdXRfR19ndGZfbVJOQVtbaV1dW1tqXV0sCiAgICAgICAgICAgICAgICAjICAgICBwYXN0ZTAoCiAgICAgICAgICAgICAgICAjICAgICAgICAgcGF0aF9HX21STkEsICIvRzFfbWtjLSIsIGdzdWIoImsiLCAiIiwgaSksICJfIiwKICAgICAgICAgICAgICAgICMgICAgICAgICBnc3ViKCJiZWxvd18iLCAiZ3RlLXBjdGwtIiwgaiksICIuZ3RmIgogICAgICAgICAgICAgICAgIyAgICAgKQogICAgICAgICAgICAgICAgIyApCiAgICAgICAgICAgIH0gZWxzZSBpZihiYXNlOjppc1RSVUUoayA9PSBwYXRoX0dfZXhvbikpIHsKICAgICAgICAgICAgICAgIG91dGZpbGUgPC0gcGFzdGUwKAogICAgICAgICAgICAgICAgICAgIHBhdGhfR19leG9uLCAiL0cxX21rYy0iLCBnc3ViKCJrIiwgIiIsIGkpLCAiXyIsCiAgICAgICAgICAgICAgICAgICAgZ3N1YigiYmVsb3dfIiwgImd0ZS1wY3RsLSIsIGopLCAiLmd0ZiIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgY2F0KCJTYXZpbmcgRzEiLCBpLCBqLCAiaW4iLCBrLCAiXG4iKQogICAgICAgICAgICAgICAgY2F0KHBhc3RlMChvdXRmaWxlLCAiXG4iKSkKICAgICAgICAgICAgICAgIGNhdCgiXG5cbiIpCiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICMgb3V0X0dfY29udiA8LSBHZW5vbWljUmFuZ2VzOjptYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoCiAgICAgICAgICAgICAgICAjICAgICBvdXRfR19ndGZfZXhvbltbaV1dW1tqXV0sIGtlZXAuZXh0cmEuY29sdW1ucyA9IFRSVUUKICAgICAgICAgICAgICAgICMgKQogICAgICAgICAgICAgICAgIyAKICAgICAgICAgICAgICAgICMgcnRyYWNrbGF5ZXI6OmV4cG9ydCgKICAgICAgICAgICAgICAgICMgICAgIG91dF9HX2d0Zl9leG9uW1tpXV1bW2pdXSwKICAgICAgICAgICAgICAgICMgICAgIHBhc3RlMCgKICAgICAgICAgICAgICAgICMgICAgICAgICBwYXRoX0dfZXhvbiwgIi9HMV9ta2MtIiwgZ3N1YigiayIsICIiLCBpKSwgIl8iLAogICAgICAgICAgICAgICAgIyAgICAgICAgIGdzdWIoImJlbG93XyIsICJndGUtcGN0bC0iLCBqKSwgIi5ndGYiCiAgICAgICAgICAgICAgICAjICAgICApCiAgICAgICAgICAgICAgICAjICkKICAgICAgICAgICAgfSBlbHNlIGlmKGJhc2U6OmlzVFJVRShrID09IHBhdGhfR19DRFMpKSB7CiAgICAgICAgICAgICAgICBvdXRmaWxlIDwtIHBhc3RlMCgKICAgICAgICAgICAgICAgICAgICBwYXRoX0dfQ0RTLCAiL0cxX21rYy0iLCBnc3ViKCJrIiwgIiIsIGkpLCAiXyIsCiAgICAgICAgICAgICAgICAgICAgZ3N1YigiYmVsb3dfIiwgImd0ZS1wY3RsLSIsIGopLCAiLmd0ZiIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgY2F0KCJTYXZpbmcgRzEiLCBpLCBqLCAiaW4iLCBrLCAiXG4iKQogICAgICAgICAgICAgICAgY2F0KHBhc3RlMChvdXRmaWxlLCAiXG4iKSkKICAgICAgICAgICAgICAgIGNhdCgiXG5cbiIpCiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICMgb3V0X0dfY29udiA8LSBHZW5vbWljUmFuZ2VzOjptYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoCiAgICAgICAgICAgICAgICAjICAgICBvdXRfR19ndGZfQ0RTW1tpXV1bW2pdXSwga2VlcC5leHRyYS5jb2x1bW5zID0gVFJVRQogICAgICAgICAgICAgICAgIyApCiAgICAgICAgICAgICAgICAjIAogICAgICAgICAgICAgICAgIyBydHJhY2tsYXllcjo6ZXhwb3J0KAogICAgICAgICAgICAgICAgIyAgICAgb3V0X0dfZ3RmX0NEU1tbaV1dW1tqXV0sCiAgICAgICAgICAgICAgICAjICAgICBwYXN0ZTAoCiAgICAgICAgICAgICAgICAjICAgICAgICAgcGF0aF9HX0NEUywgIi9HMV9ta2MtIiwgZ3N1YigiayIsICIiLCBpKSwgIl8iLAogICAgICAgICAgICAgICAgIyAgICAgICAgIGdzdWIoImJlbG93XyIsICJndGUtcGN0bC0iLCBqKSwgIi5ndGYiCiAgICAgICAgICAgICAgICAjICAgICApCiAgICAgICAgICAgICAgICAjICkKICAgICAgICAgICAgfSBlbHNlIGlmKGJhc2U6OmlzVFJVRShrID09IHBhdGhfR19pbnRyb25zX2ZpbHRlcmVkKSkgewogICAgICAgICAgICAgICAgb3V0ZmlsZSA8LSBwYXN0ZTAoCiAgICAgICAgICAgICAgICAgICAgcGF0aF9HX2ludHJvbnNfZmlsdGVyZWQsICIvRzFfbWtjLSIsIGdzdWIoImsiLCAiIiwgaSksICJfIiwKICAgICAgICAgICAgICAgICAgICBnc3ViKCJiZWxvd18iLCAiZ3RlLXBjdGwtIiwgaiksICIuZ3RmIgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICBjYXQoIlNhdmluZyBHMSIsIGksIGosICJpbiIsIGssICJcbiIpCiAgICAgICAgICAgICAgICBjYXQocGFzdGUwKG91dGZpbGUsICJcbiIpKQogICAgICAgICAgICAgICAgY2F0KCJcblxuIikKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgIyBvdXRfR19jb252IDwtIEdlbm9taWNSYW5nZXM6Om1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZSgKICAgICAgICAgICAgICAgICMgICAgIG91dF9HX2d0Zl9pbnRyb25zX2ZpbHRlcmVkW1tpXV1bW2pdXSwga2VlcC5leHRyYS5jb2x1bW5zID0gVFJVRQogICAgICAgICAgICAgICAgIyApCiAgICAgICAgICAgICAgICAjIAogICAgICAgICAgICAgICAgIyBydHJhY2tsYXllcjo6ZXhwb3J0KAogICAgICAgICAgICAgICAgIyAgICAgb3V0X0dfZ3RmX2ludHJvbnNfZmlsdGVyZWRbW2ldXVtbal1dLAogICAgICAgICAgICAgICAgIyAgICAgcGFzdGUwKAogICAgICAgICAgICAgICAgIyAgICAgICAgIHBhdGhfR19pbnRyb25zX2ZpbHRlcmVkLCAiL0cxX21rYy0iLCBnc3ViKCJrIiwgIiIsIGkpLCAiXyIsCiAgICAgICAgICAgICAgICAjICAgICAgICAgZ3N1YigiYmVsb3dfIiwgImd0ZS1wY3RsLSIsIGopLCAiLmd0ZiIKICAgICAgICAgICAgICAgICMgICAgICkKICAgICAgICAgICAgICAgICMgKQogICAgICAgICAgICB9IGVsc2UgaWYoYmFzZTo6aXNUUlVFKGsgPT0gcGF0aF9RX2xvY3VzKSkgewogICAgICAgICAgICAgICAgb3V0ZmlsZSA8LSBwYXN0ZTAoCiAgICAgICAgICAgICAgICAgICAgcGF0aF9RX2xvY3VzLCAiL1FfbWtjLSIsIGdzdWIoImsiLCAiIiwgaSksICJfIiwKICAgICAgICAgICAgICAgICAgICBnc3ViKCJiZWxvd18iLCAiZ3RlLXBjdGwtIiwgaiksICIuZ3RmIgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICBjYXQoIlNhdmluZyBRIiwgaSwgaiwgImluIiwgaywgIlxuIikKICAgICAgICAgICAgICAgIGNhdChwYXN0ZTAob3V0ZmlsZSwgIlxuIikpCiAgICAgICAgICAgICAgICBjYXQoIlxuXG4iKQogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAjIG91dF9RX2NvbnYgPC0gR2Vub21pY1Jhbmdlczo6bWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKAogICAgICAgICAgICAgICAgIyAgICAgb3V0X1FfZ3RmX2xvY3VzW1tpXV1bW2pdXSwga2VlcC5leHRyYS5jb2x1bW5zID0gVFJVRQogICAgICAgICAgICAgICAgIyApCiAgICAgICAgICAgICAgICAjIAogICAgICAgICAgICAgICAgIyBydHJhY2tsYXllcjo6ZXhwb3J0KAogICAgICAgICAgICAgICAgIyAgICAgb3V0X1FfZ3RmX2xvY3VzW1tpXV1bW2pdXSwKICAgICAgICAgICAgICAgICMgICAgIHBhc3RlMCgKICAgICAgICAgICAgICAgICMgICAgICAgICBwYXRoX1FfbG9jdXMsICIvUV9ta2MtIiwgZ3N1YigiayIsICIiLCBpKSwgIl8iLAogICAgICAgICAgICAgICAgIyAgICAgICAgIGdzdWIoImJlbG93XyIsICJndGUtcGN0bC0iLCBqKSwgIi5ndGYiCiAgICAgICAgICAgICAgICAjICAgICApCiAgICAgICAgICAgICAgICAjICkKICAgICAgICAgICAgfSBlbHNlIGlmKGJhc2U6OmlzVFJVRShrID09IHBhdGhfUV9tUk5BKSkgewogICAgICAgICAgICAgICAgb3V0ZmlsZSA8LSBwYXN0ZTAoCiAgICAgICAgICAgICAgICAgICAgcGF0aF9RX21STkEsICIvUV9ta2MtIiwgZ3N1YigiayIsICIiLCBpKSwgIl8iLAogICAgICAgICAgICAgICAgICAgIGdzdWIoImJlbG93XyIsICJndGUtcGN0bC0iLCBqKSwgIi5ndGYiCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIGNhdCgiU2F2aW5nIFEiLCBpLCBqLCAiaW4iLCBrLCAiXG4iKQogICAgICAgICAgICAgICAgY2F0KHBhc3RlMChvdXRmaWxlLCAiXG4iKSkKICAgICAgICAgICAgICAgIGNhdCgiXG5cbiIpCiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICMgb3V0X1FfY29udiA8LSBHZW5vbWljUmFuZ2VzOjptYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoCiAgICAgICAgICAgICAgICAjICAgICBvdXRfUV9ndGZfbVJOQVtbaV1dW1tqXV0sIGtlZXAuZXh0cmEuY29sdW1ucyA9IFRSVUUKICAgICAgICAgICAgICAgICMgKQogICAgICAgICAgICAgICAgIyAKICAgICAgICAgICAgICAgICMgcnRyYWNrbGF5ZXI6OmV4cG9ydCgKICAgICAgICAgICAgICAgICMgICAgIG91dF9RX2d0Zl9tUk5BW1tpXV1bW2pdXSwKICAgICAgICAgICAgICAgICMgICAgIHBhc3RlMCgKICAgICAgICAgICAgICAgICMgICAgICAgICBwYXRoX1FfbVJOQSwgIi9RX21rYy0iLCBnc3ViKCJrIiwgIiIsIGkpLCAiXyIsCiAgICAgICAgICAgICAgICAjICAgICAgICAgZ3N1YigiYmVsb3dfIiwgImd0ZS1wY3RsLSIsIGopLCAiLmd0ZiIKICAgICAgICAgICAgICAgICMgICAgICkKICAgICAgICAgICAgICAgICMgKQogICAgICAgICAgICB9IGVsc2UgaWYoYmFzZTo6aXNUUlVFKGsgPT0gcGF0aF9RX2V4b24pKSB7CiAgICAgICAgICAgICAgICBvdXRmaWxlIDwtIHBhc3RlMCgKICAgICAgICAgICAgICAgICAgICBwYXRoX1FfZXhvbiwgIi9RX21rYy0iLCBnc3ViKCJrIiwgIiIsIGkpLCAiXyIsCiAgICAgICAgICAgICAgICAgICAgZ3N1YigiYmVsb3dfIiwgImd0ZS1wY3RsLSIsIGopLCAiLmd0ZiIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgY2F0KCJTYXZpbmcgUSIsIGksIGosICJpbiIsIGssICJcbiIpCiAgICAgICAgICAgICAgICBjYXQocGFzdGUwKG91dGZpbGUsICJcbiIpKQogICAgICAgICAgICAgICAgY2F0KCJcblxuIikKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgIyBvdXRfUV9jb252IDwtIEdlbm9taWNSYW5nZXM6Om1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZSgKICAgICAgICAgICAgICAgICMgICAgIG91dF9RX2d0Zl9leG9uW1tpXV1bW2pdXSwga2VlcC5leHRyYS5jb2x1bW5zID0gVFJVRQogICAgICAgICAgICAgICAgIyApCiAgICAgICAgICAgICAgICAjIAogICAgICAgICAgICAgICAgIyBydHJhY2tsYXllcjo6ZXhwb3J0KAogICAgICAgICAgICAgICAgIyAgICAgb3V0X1FfZ3RmX2V4b25bW2ldXVtbal1dLAogICAgICAgICAgICAgICAgIyAgICAgcGFzdGUwKAogICAgICAgICAgICAgICAgIyAgICAgICAgIHBhdGhfUV9leG9uLCAiL1FfbWtjLSIsIGdzdWIoImsiLCAiIiwgaSksICJfIiwKICAgICAgICAgICAgICAgICMgICAgICAgICBnc3ViKCJiZWxvd18iLCAiZ3RlLXBjdGwtIiwgaiksICIuZ3RmIgogICAgICAgICAgICAgICAgIyAgICAgKQogICAgICAgICAgICAgICAgIyApCiAgICAgICAgICAgIH0gZWxzZSBpZihiYXNlOjppc1RSVUUoayA9PSBwYXRoX1FfQ0RTKSkgewogICAgICAgICAgICAgICAgb3V0ZmlsZSA8LSBwYXN0ZTAoCiAgICAgICAgICAgICAgICAgICAgcGF0aF9RX0NEUywgIi9RX21rYy0iLCBnc3ViKCJrIiwgIiIsIGkpLCAiXyIsCiAgICAgICAgICAgICAgICAgICAgZ3N1YigiYmVsb3dfIiwgImd0ZS1wY3RsLSIsIGopLCAiLmd0ZiIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgY2F0KCJTYXZpbmcgUSIsIGksIGosICJpbiIsIGssICJcbiIpCiAgICAgICAgICAgICAgICBjYXQocGFzdGUwKG91dGZpbGUsICJcbiIpKQogICAgICAgICAgICAgICAgY2F0KCJcblxuIikKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgIyBvdXRfUV9jb252IDwtIEdlbm9taWNSYW5nZXM6Om1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZSgKICAgICAgICAgICAgICAgICMgICAgIG91dF9RX2d0Zl9DRFNbW2ldXVtbal1dLCBrZWVwLmV4dHJhLmNvbHVtbnMgPSBUUlVFCiAgICAgICAgICAgICAgICAjICkKICAgICAgICAgICAgICAgICMgCiAgICAgICAgICAgICAgICAjIHJ0cmFja2xheWVyOjpleHBvcnQoCiAgICAgICAgICAgICAgICAjICAgICBvdXRfUV9ndGZfQ0RTW1tpXV1bW2pdXSwKICAgICAgICAgICAgICAgICMgICAgIHBhc3RlMCgKICAgICAgICAgICAgICAgICMgICAgICAgICBwYXRoX1FfQ0RTLCAiL1FfbWtjLSIsIGdzdWIoImsiLCAiIiwgaSksICJfIiwKICAgICAgICAgICAgICAgICMgICAgICAgICBnc3ViKCJiZWxvd18iLCAiZ3RlLXBjdGwtIiwgaiksICIuZ3RmIgogICAgICAgICAgICAgICAgIyAgICAgKQogICAgICAgICAgICAgICAgIyApCiAgICAgICAgICAgIH0gZWxzZSBpZihiYXNlOjppc1RSVUUoayA9PSBwYXRoX1FfaW50cm9uc19maWx0ZXJlZCkpIHsKICAgICAgICAgICAgICAgIG91dGZpbGUgPC0gcGFzdGUwKAogICAgICAgICAgICAgICAgICAgIHBhdGhfUV9pbnRyb25zX2ZpbHRlcmVkLCAiL1FfbWtjLSIsIGdzdWIoImsiLCAiIiwgaSksICJfIiwKICAgICAgICAgICAgICAgICAgICBnc3ViKCJiZWxvd18iLCAiZ3RlLXBjdGwtIiwgaiksICIuZ3RmIgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICBjYXQoIlNhdmluZyBRIiwgaSwgaiwgImluIiwgaywgIlxuIikKICAgICAgICAgICAgICAgIGNhdChwYXN0ZTAob3V0ZmlsZSwgIlxuIikpCiAgICAgICAgICAgICAgICBjYXQoIlxuXG4iKQogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAjIG91dF9RX2NvbnYgPC0gR2Vub21pY1Jhbmdlczo6bWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKAogICAgICAgICAgICAgICAgIyAgICAgb3V0X1FfZ3RmX2ludHJvbnNfZmlsdGVyZWRbW2ldXVtbal1dLCBrZWVwLmV4dHJhLmNvbHVtbnMgPSBUUlVFCiAgICAgICAgICAgICAgICAjICkKICAgICAgICAgICAgICAgICMgCiAgICAgICAgICAgICAgICAjIHJ0cmFja2xheWVyOjpleHBvcnQoCiAgICAgICAgICAgICAgICAjICAgICBvdXRfUV9ndGZfaW50cm9uc19maWx0ZXJlZFtbaV1dW1tqXV0sCiAgICAgICAgICAgICAgICAjICAgICBwYXN0ZTAoCiAgICAgICAgICAgICAgICAjICAgICAgICAgcGF0aF9RX2ludHJvbnNfZmlsdGVyZWQsICIvUV9ta2MtIiwgZ3N1YigiayIsICIiLCBpKSwgIl8iLAogICAgICAgICAgICAgICAgIyAgICAgICAgIGdzdWIoImJlbG93XyIsICJndGUtcGN0bC0iLCBqKSwgIi5ndGYiCiAgICAgICAgICAgICAgICAjICAgICApCiAgICAgICAgICAgICAgICAjICkKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KfQpgYGAKPC9kZXRhaWxzPgo8YnIgLz4K